All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.stargate.it.http.RestApiv2RowsTest Maven / Gradle / Ivy

There is a newer version: 2.1.0-BETA-19
Show newest version
/*
 * Copyright The Stargate Authors
 *
 * Licensed 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 io.stargate.it.http;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertTrue;

import com.datastax.oss.driver.api.core.data.CqlDuration;
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import io.stargate.auth.model.AuthTokenResponse;
import io.stargate.it.BaseIntegrationTest;
import io.stargate.it.driver.CqlSessionExtension;
import io.stargate.it.driver.CqlSessionSpec;
import io.stargate.it.http.models.Credentials;
import io.stargate.it.storage.StargateConnectionInfo;
import io.stargate.web.models.ApiError;
import io.stargate.web.restapi.models.ColumnDefinition;
import io.stargate.web.restapi.models.GetResponseWrapper;
import io.stargate.web.restapi.models.IndexAdd;
import io.stargate.web.restapi.models.IndexKind;
import io.stargate.web.restapi.models.PrimaryKey;
import io.stargate.web.restapi.models.RESTResponseWrapper;
import io.stargate.web.restapi.models.SuccessResponse;
import io.stargate.web.restapi.models.TableAdd;
import io.stargate.web.restapi.models.TableResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import net.jcip.annotations.NotThreadSafe;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.extension.ExtendWith;

/**
 * Integration tests for REST API v2 that cover Row access CRUD methods.
 *
 * 

Due to historical reasons, some Scheme CRUD tests are also included until moved out to new, * more granular IT classes. */ @NotThreadSafe @ExtendWith(CqlSessionExtension.class) @CqlSessionSpec() public class RestApiv2RowsTest extends BaseIntegrationTest { private String keyspaceName; private String tableName; private static String authToken; private String host; private String restUrlBase; // NOTE! Does not automatically disable exception on unknown properties to have // stricter matching of expected return types: if needed, can override on // per-ObjectReader basis private static final ObjectMapper objectMapper = new ObjectMapper(); private static final ObjectReader LIST_OF_MAPS_GETRESPONSE_READER = objectMapper.readerFor(ListOfMapsGetResponseWrapper.class); static class ListOfMapsGetResponseWrapper extends GetResponseWrapper>> { public ListOfMapsGetResponseWrapper() { super(-1, null, null); } } static class JsonNodeGetResponseWrapper extends GetResponseWrapper { public JsonNodeGetResponseWrapper() { super(-1, null, null); } } // TablesResource specifies only as "Map" but it looks to me like: static class NameResponse { public String name; } @BeforeEach public void setup(TestInfo testInfo, StargateConnectionInfo cluster) throws IOException { host = "http://" + cluster.seedAddress(); restUrlBase = host + ":8082"; String body = RestUtils.post( "", String.format("%s:8081/v1/auth/token/generate", host), objectMapper.writeValueAsString(new Credentials("cassandra", "cassandra")), HttpStatus.SC_CREATED); AuthTokenResponse authTokenResponse = objectMapper.readValue(body, AuthTokenResponse.class); authToken = authTokenResponse.getAuthToken(); assertThat(authToken).isNotNull(); Optional name = testInfo.getTestMethod().map(Method::getName); assertThat(name).isPresent(); String testName = name.get(); keyspaceName = "ks_" + testName + "_" + System.currentTimeMillis(); tableName = "tbl_" + testName + "_" + System.currentTimeMillis(); } /* /************************************************************************ /* Test methods for Index CRUD operations /************************************************************************ */ /* /************************************************************************ /* Test methods for Row Access CRUD operations /************************************************************************ */ @Test public void getRowsWithQuery() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); RestUtils.post( authToken, String.format("%s/v2/keyspaces/%s/%s", restUrlBase, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); String whereClause = String.format("{\"id\":{\"$eq\":\"%s\"}}", rowIdentifier); String body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s?where=%s", restUrlBase, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); JsonNodeGetResponseWrapper getResponseWrapper = objectMapper.readValue(body, JsonNodeGetResponseWrapper.class); JsonNode data = getResponseWrapper.getData(); assertThat(data.size()).isEqualTo(1); assertThat(data.at("/0/id").asText()).isEqualTo(rowIdentifier); assertThat(data.at("/0/firstName").asText()).isEqualTo("John"); } @Test public void getRowsWithQuery2Filters() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "age int", "firstName text"), Collections.singletonList("id"), Arrays.asList("age", "firstName")); insertTestTableRows( Arrays.asList( Arrays.asList("id 1", "firstName Bob", "age 25"), Arrays.asList("id 1", "firstName Dave", "age 40"), Arrays.asList("id 1", "firstName Fred", "age 63"))); // Test the case where we have 2 filters ($gt and $lt) for one field String whereClause = "{\"id\":{\"$eq\":\"1\"},\"age\":{\"$gt\":30,\"$lt\":50}}"; String body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s?where=%s", restUrlBase, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); JsonNodeGetResponseWrapper getResponseWrapper = objectMapper.readValue(body, JsonNodeGetResponseWrapper.class); JsonNode data = getResponseWrapper.getData(); assertThat(data.size()).isEqualTo(1); assertThat(data.at("/0/id").asText()).isEqualTo("1"); assertThat(data.at("/0/firstName").asText()).isEqualTo("Dave"); } @Test public void getRowsWithQueryAndPaging() throws IOException { String rowIdentifier = setupClusteringTestCase(); String whereClause = String.format("{\"id\":{\"$eq\":\"%s\"}}", rowIdentifier); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s?where=%s&page-size=1", host, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(1); assertThat(getResponseWrapper.getPageState()).isNotEmpty(); assertThat(data.get(0).get("id")).isEqualTo(1); assertThat(data.get(0).get("firstName")).isEqualTo("John"); assertThat(data.get(0).get("expense_id")).isEqualTo(1); } @Test public void getRowsWithQueryAndRaw() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); String whereClause = String.format("{\"id\":{\"$eq\":\"%s\"}}", rowIdentifier); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s?where=%s&raw=true", host, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); List> data = objectMapper.readValue(body, new TypeReference>>() {}); assertThat(data.get(0).get("id")).isEqualTo(rowIdentifier); assertThat(data.get(0).get("firstName")).isEqualTo("John"); } @Test public void getRowsWithQueryAndSort() throws IOException { String rowIdentifier = setupClusteringTestCase(); String whereClause = String.format("{\"id\":{\"$eq\":\"%s\"}}", rowIdentifier); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s?where=%s&sort={\"expense_id\":\"desc\"}", host, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(2); assertThat(data.get(0).get("id")).isEqualTo(1); assertThat(data.get(0).get("firstName")).isEqualTo("John"); assertThat(data.get(0).get("expense_id")).isEqualTo(2); } @Test public void getRowsWithQueryRawAndSort() throws IOException { String rowIdentifier = setupClusteringTestCase(); String whereClause = String.format("{\"id\":{\"$eq\":\"%s\"}}", rowIdentifier); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s?where=%s&sort={\"expense_id\":\"desc\"}&raw=true", host, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); List> data = objectMapper.readValue(body, new TypeReference>>() {}); assertThat(data.size()).isEqualTo(2); assertThat(data.get(0).get("id")).isEqualTo(1); assertThat(data.get(0).get("firstName")).isEqualTo("John"); assertThat(data.get(0).get("expense_id")).isEqualTo(2); } @Test public void getRowsWithQueryAndInvalidSort() throws IOException { String rowIdentifier = setupClusteringTestCase(); String whereClause = String.format("{\"id\":{\"$eq\":\"%s\"}}", rowIdentifier); RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s?where=%s&sort={\"expense_id\"\":\"desc\"}", host, keyspaceName, tableName, whereClause), HttpStatus.SC_BAD_REQUEST); } @Test public void getRowsWithNotFound() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); String whereClause = "{\"id\":{\"$eq\":\"f0014be3-b69f-4884-b9a6-49765fb40df3\"}}"; String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s?where=%s&fields=id,firstName", host, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(0); assertThat(data).isEmpty(); } @Test public void getRowsWithInQuery() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "firstName text"), Collections.singletonList("id"), Collections.singletonList("firstName")); insertTestTableRows( Arrays.asList( Arrays.asList("id 1", "firstName John"), Arrays.asList("id 1", "firstName Sarah"), Arrays.asList("id 2", "firstName Jane"))); String whereClause = "{\"id\":{\"$eq\":\"1\"},\"firstName\":{\"$in\":[\"Sarah\"]}}"; String body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s?where=%s&raw=true", restUrlBase, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); List> data = objectMapper.readValue(body, new TypeReference>>() {}); assertThat(data.size()).isEqualTo(1); assertThat(data.get(0).get("id")).isEqualTo("1"); assertThat(data.get(0).get("firstName")).isEqualTo("Sarah"); // Let's also test with three values (of which 2 match) whereClause = "{\"id\":{\"$eq\":\"1\"},\"firstName\":{\"$in\":[\"Sarah\", \"Bob\", \"John\" ]}}"; body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s?where=%s&raw=true", restUrlBase, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); JsonNode root = objectMapper.readTree(body); Set namesReceived = new LinkedHashSet<>( Arrays.asList( root.path(0).path("firstName").asText(), root.path(1).path("firstName").asText())); Set namesExpected = new LinkedHashSet<>(Arrays.asList("Sarah", "John")); assertThat(namesReceived).isEqualTo(namesExpected); } // 04-Jan-2022, tatu: Verifies existing behavior of Stargate REST 1.0, // which seems to differ from Documents API. Whether right or wrong, // this behavior is what exists. @Test public void getRowsWithExistsQuery() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "firstName text", "enabled boolean"), Collections.singletonList("id"), Collections.singletonList("enabled")); insertTestTableRows( Arrays.asList( Arrays.asList("id 1", "firstName Bob", "enabled false"), Arrays.asList("id 1", "firstName Dave", "enabled true"), Arrays.asList("id 2", "firstName Frank", "enabled true"), Arrays.asList("id 1", "firstName Pete", "enabled false"))); String whereClause = "{\"id\":{\"$eq\":\"1\"},\"enabled\":{\"$exists\":true}}"; String body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s?where=%s&raw=true", restUrlBase, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); JsonNode json = objectMapper.readTree(body); assertThat(json.size()).isEqualTo(1); assertThat(json.at("/0/firstName").asText()).isEqualTo("Dave"); } @Test public void getRowsWithSetContainsQuery() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "tags set", "firstName text"), Collections.singletonList("id"), Collections.singletonList("firstName")); // Cannot query against non-key columns, unless there's an index, so: createTestIndex(keyspaceName, tableName, "tags", "tags_index", false, IndexKind.VALUES); insertTestTableRows( Arrays.asList( Arrays.asList("id 1", "firstName Bob", "tags {'a','b'}"), Arrays.asList("id 1", "firstName Dave", "tags {'b','c'}"), Arrays.asList("id 1", "firstName Fred", "tags {'x'}"))); // First, no match String whereClause = "{\"id\":{\"$eq\":\"1\"},\"tags\":{\"$contains\":\"z\"}}"; String body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s?where=%s&raw=true", restUrlBase, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); JsonNode json = objectMapper.readTree(body); assertThat(json.size()).isEqualTo(0); // and then 2 matches whereClause = "{\"id\":{\"$eq\":\"1\"},\"tags\": {\"$contains\": \"b\"}}"; body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s?where=%s&raw=true", restUrlBase, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); json = objectMapper.readTree(body); assertThat(json.size()).isEqualTo(2); assertThat(json.at("/0/firstName").asText()).isEqualTo("Bob"); assertThat(json.at("/1/firstName").asText()).isEqualTo("Dave"); // 05-Jan-2022, tatu: API does allow specifying an ARRAY of things to contain, but, // alas, resulting query will not work ("need to ALLOW FILTERING"). // So not testing that case. } @Test public void getRowsWithContainsKeyQuery() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "attributes map", "firstName text"), Collections.singletonList("id"), Collections.singletonList("firstName")); // Cannot query against non-key columns, unless there's an index, so: createTestIndex( keyspaceName, tableName, "attributes", "attributes_map_index", false, IndexKind.KEYS); insertTestTableRows( Arrays.asList( Arrays.asList("id 1", "firstName Bob", "attributes {'a':'1'}"), Arrays.asList("id 1", "firstName Dave", "attributes {'b':'2'}"), Arrays.asList("id 1", "firstName Fred", "attributes {'c':'3'}"))); // First, no match String whereClause = "{\"id\":{\"$eq\":\"1\"},\"attributes\":{\"$containsKey\":\"d\"}}"; String body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s?where=%s&raw=true", restUrlBase, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); JsonNode json = objectMapper.readTree(body); assertThat(json.size()).isEqualTo(0); // and then a single match whereClause = "{\"id\":{\"$eq\":\"1\"},\"attributes\":{\"$containsKey\":\"b\"}}"; body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s?where=%s&raw=true", restUrlBase, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); json = objectMapper.readTree(body); assertThat(json.size()).isEqualTo(1); assertThat(json.at("/0/firstName").asText()).isEqualTo("Dave"); // [stargate#2577]: Maps are represented using wrapper style in SGv1/RESTv2 final JsonNode expAttrs = objectMapper.readTree("[{\"key\":\"b\",\"value\":\"2\"}]"); assertThat(json.at("/0/attributes")).isEqualTo(expAttrs); // 06-Jan-2022, tatu: API does allow specifying an ARRAY of things to contain, but, // alas, resulting query will not work ("need to ALLOW FILTERING"). // So not testing that case. } @Test public void getRowsWithContainsEntryQuery() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "attributes map", "firstName text"), Collections.singletonList("id"), Collections.singletonList("firstName")); // Cannot query against non-key columns, unless there's an index, so: createTestIndex( keyspaceName, tableName, "attributes", "attributes_map_index", false, IndexKind.ENTRIES); insertTestTableRows( Arrays.asList( Arrays.asList("id 1", "firstName Bob", "attributes {'a':'1'}"), Arrays.asList("id 1", "firstName Dave", "attributes {'b':'2'}"), Arrays.asList("id 1", "firstName Fred", "attributes {'c':'3'}"))); // First, no match String whereClause = "{\"id\":{\"$eq\":\"1\"},\"attributes\":{\"$containsEntry\":{\"key\":\"b\",\"value\":\"1\"}}}"; String body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s?where=%s&raw=true", restUrlBase, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); JsonNode json = objectMapper.readTree(body); assertThat(json.size()).isEqualTo(0); // and then a single match whereClause = "{\"id\":{\"$eq\":\"1\"},\"attributes\":{\"$containsEntry\":{\"key\":\"c\",\"value\":\"3\"}}}"; body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s?where=%s&raw=true", restUrlBase, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); json = objectMapper.readTree(body); assertThat(json.size()).isEqualTo(1); assertThat(json.at("/0/firstName").asText()).isEqualTo("Fred"); // [stargate#2577]: Maps are represented using wrapper style in SGv1/RESTv2 final JsonNode expAttrs = objectMapper.readTree("[{\"key\":\"c\",\"value\":\"3\"}]"); assertThat(json.at("/0/attributes")).isEqualTo(expAttrs); } @Test public void getRowsWithTimestampQuery() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "firstName text", "created timestamp"), Collections.singletonList("id"), Collections.singletonList("created")); String timestamp = "2021-04-23T18:42:22.139Z"; insertTestTableRows( Arrays.asList( Arrays.asList("id 1", "firstName John", "created " + timestamp), Arrays.asList("id 1", "firstName Sarah", "created 2021-04-20T18:42:22.139Z"), Arrays.asList("id 2", "firstName Jane", "created 2021-04-22T18:42:22.139Z"))); String whereClause = String.format("{\"id\":{\"$eq\":\"1\"},\"created\":{\"$in\":[\"%s\"]}}", timestamp); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s?where=%s&raw=true", host, keyspaceName, tableName, whereClause), HttpStatus.SC_OK); List> data = objectMapper.readValue(body, new TypeReference>>() {}); assertThat(data.size()).isEqualTo(1); assertThat(data.get(0).get("id")).isEqualTo("1"); assertThat(data.get(0).get("firstName")).isEqualTo("John"); assertThat(data.get(0).get("created")).isEqualTo(timestamp); } @Test public void getRowsWithDurationValue() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "firstName text", "time duration"), Collections.singletonList("id"), Collections.singletonList("firstName")); CqlDuration expDuration = CqlDuration.from("2w"); insertTestTableRows( Arrays.asList( Arrays.asList("id 1", "firstName John", "time 2d"), Arrays.asList("id 2", "firstName Sarah", "time " + expDuration), Arrays.asList("id 3", "firstName Jane", "time 30h20m"))); String body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s/%s?raw=true", restUrlBase, keyspaceName, tableName, "2"), HttpStatus.SC_OK); JsonNode json = objectMapper.readTree(body); assertThat(json.size()).isEqualTo(1); assertThat(json.at("/0/firstName").asText()).isEqualTo("Sarah"); // NOTE: "2 weeks" may become "14 days" (or vice versa); so let's compare CqlDuration equality assertThat(CqlDuration.from(json.at("/0/time").asText())).isEqualTo(expDuration); } @Test public void getAllRowsWithPaging() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "firstName text"), Collections.singletonList("id"), null); List> expRows = insertTestTableRows( Arrays.asList( Arrays.asList("id 1", "firstName Jonh"), Arrays.asList("id 2", "firstName Jane"), Arrays.asList("id 3", "firstName Scott"), Arrays.asList("id 4", "firstName April"))); final List> allRows = new ArrayList<>(); // get first page String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/rows?page-size=2", host, keyspaceName, tableName), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); assertThat(getResponseWrapper.getCount()).isEqualTo(2); assertThat(getResponseWrapper.getPageState()).isNotEmpty(); allRows.addAll(getResponseWrapper.getData()); // get second page String pageState = getResponseWrapper.getPageState(); body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/rows?page-size=2&page-state=%s", host, keyspaceName, tableName, pageState), HttpStatus.SC_OK); getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); assertThat(getResponseWrapper.getCount()).isEqualTo(2); allRows.addAll(getResponseWrapper.getData()); // ensure no more pages: we do still get PagingState, but no more rows pageState = getResponseWrapper.getPageState(); assertThat(pageState).isNotEmpty(); body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/rows?page-size=2&page-state=%s", host, keyspaceName, tableName, pageState), HttpStatus.SC_OK); getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); assertThat(getResponseWrapper.getCount()).isEqualTo(0); assertThat(getResponseWrapper.getPageState()).isNull(); // Since order in which we get these is arbitrary (wrt partition key), need // to go from List to Set assertThat(new LinkedHashSet(allRows)).isEqualTo(new LinkedHashSet(expRows)); } @Test public void getAllRowsNoPaging() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "firstName text"), Collections.singletonList("id"), null); List> expRows = insertTestTableRows( Arrays.asList( Arrays.asList("id 1", "firstName Jonh"), Arrays.asList("id 2", "firstName Jane"), Arrays.asList("id 3", "firstName Scott"), Arrays.asList("id 4", "firstName April"))); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/rows?fields=id, firstName", host, keyspaceName, tableName), HttpStatus.SC_OK); @SuppressWarnings("rawtypes") ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); assertThat(getResponseWrapper.getCount()).isEqualTo(4); // Alas, due to "id" as partition key, ordering is arbitrary; so need to // convert from List to something like Set List> rows = getResponseWrapper.getData(); assertThat(rows.size()).isEqualTo(4); assertThat(new LinkedHashSet<>(rows)).isEqualTo(new LinkedHashSet<>(expRows)); } @Test public void getInvalidWhereClause() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); String whereClause = "{\"invalid_field\":{\"$eq\":\"test\"}}"; String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s?where=%s", host, keyspaceName, tableName, whereClause), HttpStatus.SC_BAD_REQUEST); ApiError response = objectMapper.readValue(body, ApiError.class); assertThat(response.getCode()).isEqualTo(HttpStatus.SC_BAD_REQUEST); assertThat(response.getDescription()) .isEqualTo("Bad request: Unknown field name 'invalid_field'."); } @Test public void getRows() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); // To try to ensure we actually find the right entry, create one other entry first Map row = new HashMap<>(); row.put("id", UUID.randomUUID().toString()); row.put("firstName", "Michael"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); // and then the row we are actually looking for: String rowIdentifier = UUID.randomUUID().toString(); row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); // Verify we fetch one and only one entry assertThat(getResponseWrapper.getCount()).isEqualTo(1); assertThat(data.size()).isEqualTo(1); // and that its contents match assertThat(data.get(0).get("id")).isEqualTo(rowIdentifier); assertThat(data.get(0).get("firstName")).isEqualTo("John"); } // Test for inserting and fetching row(s) with Tuple values: inserts using // "Stringified" (non-JSON, CQL literal) notation. @Test public void getRowsWithTupleStringified() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "data tuple", "alt_id uuid"), Collections.singletonList("id"), Collections.emptyList()); String altUid1 = UUID.randomUUID().toString(); insertTestTableRows( Arrays.asList( // Put UUID for the first row; leave second one empty/missing Arrays.asList("id 1", "data (28,false,'foobar')", "alt_id " + altUid1), Arrays.asList("id 2", "data (39,true,'bingo')"))); JsonNode json = readRawRowsBySingleKey(keyspaceName, tableName, "2"); assertThat(json.size()).isEqualTo(1); assertThat(json.at("/0/id").asText()).isEqualTo("2"); assertThat(json.at("/0/data/0").intValue()).isEqualTo(39); assertThat(json.at("/0/data/1").booleanValue()).isTrue(); assertThat(json.at("/0/data").size()).isEqualTo(3); assertTrue(json.at("/0/alt_id").isNull()); } // Test for inserting and fetching row(s) with Tuple values: inserts using // standard JSON payload @Test public void getRowsWithTupleTyped() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "data tuple", "alt_id uuid"), Collections.singletonList("id"), Collections.emptyList()); String altUid1 = UUID.randomUUID().toString(); insertTypedTestTableRows( Arrays.asList( ImmutableMap.of( "id", "1", "data", Arrays.asList(28, false, "foobar"), "alt_id", altUid1), ImmutableMap.of( "id", "2", "data", Arrays.asList(39, true, "bingo"), "alt_id", objectMapper.nullNode()))); JsonNode json = readRawRowsBySingleKey(keyspaceName, tableName, "2"); assertThat(json.size()).isEqualTo(1); assertThat(json.at("/0/id").asText()).isEqualTo("2"); assertThat(json.at("/0/data/0").intValue()).isEqualTo(39); assertThat(json.at("/0/data/1").booleanValue()).isTrue(); assertThat(json.at("/0/data").size()).isEqualTo(3); assertTrue(json.at("/0/alt_id").isNull()); } @Test public void getRowsWithUDT() throws IOException { createTestKeyspace(keyspaceName); // create UDT: note -- UDT names must be lower-case it seems (mixed case fails) String udtString = "{\"name\": \"testUDT\", \"fields\":" + "[{\"name\":\"name\",\"typeDefinition\":\"text\"}," + "{\"name\":\"age\",\"typeDefinition\":\"int\"}]}"; RestUtils.post( authToken, String.format("%s/v2/schemas/keyspaces/%s/types", restUrlBase, keyspaceName), udtString, HttpStatus.SC_CREATED); createTestTable( tableName, Arrays.asList("id text", "details testUDT"), Collections.singletonList("id"), Collections.emptyList()); insertTestTableRows( Arrays.asList( Arrays.asList("id 1", "details {name:'Bob',age:36}"), Arrays.asList("id 2", "details {name:'Alice',age:29}"), Arrays.asList("id 3", "details {name:'Peter',age:75}"))); String body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s/%s?raw=true", restUrlBase, keyspaceName, tableName, "2"), HttpStatus.SC_OK); JsonNode json = objectMapper.readTree(body); assertThat(json.size()).isEqualTo(1); assertThat(json.at("/0/details/name").asText()).isEqualTo("Alice"); assertThat(json.at("/0/details/age").intValue()).isEqualTo(29); } @Test public void getRowsSort() throws IOException { String rowIdentifier = setupClusteringTestCase(); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?sort={\"expense_id\":\"desc\"}", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(2); assertThat(data.get(0).get("id")).isEqualTo(1); assertThat(data.get(0).get("firstName")).isEqualTo("John"); assertThat(data.get(0).get("expense_id")).isEqualTo(2); } @Test public void getRowsPaging() throws IOException { String rowIdentifier = setupClusteringTestCase(); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?page-size=1", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(1); assertThat(getResponseWrapper.getPageState()).isNotEmpty(); assertThat(data.get(0).get("id")).isEqualTo(1); assertThat(data.get(0).get("firstName")).isEqualTo("John"); assertThat(data.get(0).get("expense_id")).isEqualTo(1); } @Test public void getRowsNotFound() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, "f0014be3-b69f-4884-b9a6-49765fb40df3"), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(0); assertThat(data).isEmpty(); } @Test public void getRowsRaw() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?raw=true", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); List> data = objectMapper.readValue(body, new TypeReference>>() {}); assertThat(data.get(0).get("id")).isEqualTo(rowIdentifier); assertThat(data.get(0).get("firstName")).isEqualTo("John"); } @Test public void getRowsRawAndSort() throws IOException { String rowIdentifier = setupClusteringTestCase(); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?sort={\"expense_id\": \"desc\"}&raw=true", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); List> data = objectMapper.readValue(body, new TypeReference>>() {}); assertThat(data.size()).isEqualTo(2); assertThat(data.get(0).get("id")).isEqualTo(1); assertThat(data.get(0).get("firstName")).isEqualTo("John"); assertThat(data.get(0).get("expense_id")).isEqualTo(2); } @Test public void getRowsPartitionKeyOnly() throws IOException { String rowIdentifier = setupClusteringTestCase(); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(2); assertThat(data.get(0).get("id")).isEqualTo(1); assertThat(data.get(0).get("expense_id")).isEqualTo(1); assertThat(data.get(1).get("id")).isEqualTo(1); assertThat(data.get(1).get("expense_id")).isEqualTo(2); } @Test public void getRowsPartitionAndClusterKeys() throws IOException { String rowIdentifier = setupClusteringTestCase(); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s/2", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(1); assertThat(data.get(0).get("id")).isEqualTo(1); assertThat(data.get(0).get("firstName")).isEqualTo("John"); assertThat(data.get(0).get("expense_id")).isEqualTo(2); } @Test public void getRowsWithMixedClustering() throws IOException { setupMixedClusteringTestCase(); String body = RestUtils.get( authToken, String.format("%s:8082/v2/keyspaces/%s/%s/1/one/-1", host, keyspaceName, tableName), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(2); assertThat(data.get(0).get("v")).isEqualTo(9); assertThat(data.get(1).get("v")).isEqualTo(19); body = RestUtils.get( authToken, String.format("%s:8082/v2/keyspaces/%s/%s/1/one/-1/20", host, keyspaceName, tableName), HttpStatus.SC_OK); getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(1); assertThat(data.get(0).get("v")).isEqualTo(19); } @Test public void addRow() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); String body = RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); Map rowResponse = objectMapper.readValue(body, new TypeReference>() {}); assertThat(rowResponse.get("id")).isEqualTo(rowIdentifier); } @Test public void addRowWithCounter() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "counter counter"), Collections.singletonList("id"), null); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("counter", "+1"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_BAD_REQUEST); } @Test public void addRowWithList() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("name text", "email list"), Collections.singletonList("name"), null); Map row = new HashMap<>(); row.put("name", "alice"); row.put("email", "['[email protected]','[email protected]']"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?raw=true", host, keyspaceName, tableName, "alice"), HttpStatus.SC_OK); List> data = objectMapper.readValue(body, new TypeReference>>() {}); assertThat(data.get(0).get("name")).isEqualTo("alice"); assertThat(data.get(0).get("email")) .isEqualTo(Arrays.asList("[email protected]", "[email protected]")); } @Test public void addRowInvalidField() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("invalid_field", "John"); String body = RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_BAD_REQUEST); ApiError response = objectMapper.readValue(body, ApiError.class); assertThat(response.getCode()).isEqualTo(HttpStatus.SC_BAD_REQUEST); assertThat(response.getDescription()) .isEqualTo("Bad request: Unknown field name 'invalid_field'."); } @Test public void addRowWithInvalidJson() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), "{\"id\": \"af2603d2-8c03-11eb-a03f-0ada685e0000\",\"firstName: \"john\"}", HttpStatus.SC_BAD_REQUEST); } @Test public void updateRow() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); RestUtils.post( authToken, String.format("%s/v2/keyspaces/%s/%s", restUrlBase, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); Map rowUpdate = new HashMap<>(); rowUpdate.put("firstName", "Robert"); rowUpdate.put("lastName", "Plant"); String body = RestUtils.put( authToken, String.format( "%s/v2/keyspaces/%s/%s/%s", restUrlBase, keyspaceName, tableName, rowIdentifier), objectMapper.writeValueAsString(rowUpdate), HttpStatus.SC_OK); Map data = readWrappedRESTResponse(body, Map.class); assertThat(data).containsAllEntriesOf(rowUpdate); } @Test public void updateRowRaw() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); Map rowUpdate = new HashMap<>(); rowUpdate.put("firstName", "Robert"); rowUpdate.put("lastName", "Plant"); String body = RestUtils.put( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?raw=true", host, keyspaceName, tableName, rowIdentifier), objectMapper.writeValueAsString(rowUpdate), HttpStatus.SC_OK); @SuppressWarnings("unchecked") Map data = objectMapper.readValue(body, Map.class); assertThat(data).containsAllEntriesOf(rowUpdate); // Also verify that we can "delete" lastName Map update2 = new HashMap<>(); update2.put("firstName", "Roger"); update2.put("lastName", null); RestUtils.put( authToken, String.format( "%s/v2/keyspaces/%s/%s/%s", restUrlBase, keyspaceName, tableName, rowIdentifier), objectMapper.writeValueAsString(update2), HttpStatus.SC_OK); // And that change actually occurs JsonNode json = readRawRowsBySingleKey(keyspaceName, tableName, rowIdentifier); assertThat(json.size()).isEqualTo(1); assertThat(json.at("/0/id").asText()).isEqualTo(rowIdentifier); assertThat(json.at("/0/firstName").asText()).isEqualTo("Roger"); assertTrue(json.at("/0/lastName").isNull()); assertTrue(json.at("/0/age").isNull()); assertThat(json.at("/0").size()).isEqualTo(4); } @Test public void updateRowWithCounter() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "counter counter"), Collections.singletonList("id"), null); String rowIdentifier = UUID.randomUUID().toString(); Map row = Collections.singletonMap("counter", "+1"); String body = RestUtils.put( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?raw=true", host, keyspaceName, tableName, rowIdentifier), objectMapper.writeValueAsString(row), HttpStatus.SC_OK); @SuppressWarnings("unchecked") Map data = objectMapper.readValue(body, Map.class); assertThat(data).containsAllEntriesOf(row); body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?raw=true", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); List> dataList = objectMapper.readValue(body, new TypeReference>>() {}); assertThat(dataList.get(0).get("id")).isEqualTo(rowIdentifier); assertThat(dataList.get(0).get("counter")).isEqualTo("1"); body = RestUtils.put( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?raw=true", host, keyspaceName, tableName, rowIdentifier), objectMapper.writeValueAsString(row), HttpStatus.SC_OK); @SuppressWarnings("unchecked") Map dataMap = objectMapper.readValue(body, Map.class); assertThat(dataMap).containsAllEntriesOf(row); body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?raw=true", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); dataList = objectMapper.readValue(body, new TypeReference>>() {}); assertThat(dataList.get(0).get("id")).isEqualTo(rowIdentifier); assertThat(dataList.get(0).get("counter")).isEqualTo("2"); } @Test public void updateRowWithMultipleCounters() throws IOException { createTestKeyspace(keyspaceName); createTestTable( tableName, Arrays.asList("id text", "counter1 counter", "counter2 counter"), Collections.singletonList("id"), null); String rowIdentifier = UUID.randomUUID().toString(); Map rowUpdate = new HashMap<>(); rowUpdate.put("counter1", "+1"); rowUpdate.put("counter2", "-1"); String body = RestUtils.put( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?raw=true", host, keyspaceName, tableName, rowIdentifier), objectMapper.writeValueAsString(rowUpdate), HttpStatus.SC_OK); @SuppressWarnings("unchecked") Map data = objectMapper.readValue(body, Map.class); assertThat(data).containsAllEntriesOf(rowUpdate); body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?raw=true", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); List> dataList = objectMapper.readValue(body, new TypeReference>>() {}); assertThat(dataList.get(0).get("id")).isEqualTo(rowIdentifier); assertThat(dataList.get(0).get("counter1")).isEqualTo("1"); assertThat(dataList.get(0).get("counter2")).isEqualTo("-1"); } @Test public void updateRowWithInvalidJson() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); RestUtils.put( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), "{\"firstName\": \"Robert,\"lastName\": \"Plant\"}", HttpStatus.SC_BAD_REQUEST); } @Test public void patchRow() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); row.put("lastName", "Doe"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); Map rowUpdate = new HashMap<>(); rowUpdate.put("firstName", "Jane"); String body = RestUtils.patch( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), objectMapper.writeValueAsString(rowUpdate), HttpStatus.SC_OK); Map patchData = readWrappedRESTResponse(body, Map.class); assertThat(patchData).containsAllEntriesOf(rowUpdate); body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(data.get(0).get("id")).isEqualTo(rowIdentifier); assertThat(data.get(0).get("firstName")).isEqualTo("Jane"); assertThat(data.get(0).get("lastName")).isEqualTo("Doe"); } @Test public void patchRowRaw() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); row.put("lastName", "Doe"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); Map rowUpdate = new HashMap<>(); rowUpdate.put("firstName", "Jane"); String body = RestUtils.patch( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s?raw=true", host, keyspaceName, tableName, rowIdentifier), objectMapper.writeValueAsString(rowUpdate), HttpStatus.SC_OK); @SuppressWarnings("unchecked") Map patchData = objectMapper.readValue(body, Map.class); assertThat(patchData).containsAllEntriesOf(rowUpdate); body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(data.get(0).get("id")).isEqualTo(rowIdentifier); assertThat(data.get(0).get("firstName")).isEqualTo("Jane"); assertThat(data.get(0).get("lastName")).isEqualTo("Doe"); } @Test public void deleteRow() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); String rowIdentifier = UUID.randomUUID().toString(); Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); RestUtils.post( authToken, String.format("%s:8082/v2/keyspaces/%s/%s", host, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); RestUtils.delete( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_NO_CONTENT); } @Test public void deleteRowClustering() throws IOException { String rowIdentifier = setupClusteringTestCase(); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(2); assertThat(data.get(0).get("id")).isEqualTo(1); assertThat(data.get(0).get("expense_id")).isEqualTo(1); assertThat(data.get(1).get("id")).isEqualTo(1); assertThat(data.get(1).get("expense_id")).isEqualTo(2); RestUtils.delete( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s/1", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_NO_CONTENT); body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(1); assertThat(data.get(0).get("id")).isEqualTo(1); assertThat(data.get(0).get("expense_id")).isEqualTo(2); } @Test public void deleteRowByPartitionKey() throws IOException { String rowIdentifier = setupClusteringTestCase(); String body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(2); assertThat(data.get(0).get("id")).isEqualTo(1); assertThat(data.get(0).get("expense_id")).isEqualTo(1); assertThat(data.get(1).get("id")).isEqualTo(1); assertThat(data.get(1).get("expense_id")).isEqualTo(2); RestUtils.delete( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_NO_CONTENT); body = RestUtils.get( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_OK); getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); assertThat(getResponseWrapper.getCount()).isEqualTo(0); body = RestUtils.get( authToken, String.format("%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, "2"), HttpStatus.SC_OK); getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(1); assertThat(data.get(0).get("id")).isEqualTo(2); assertThat(data.get(0).get("firstName")).isEqualTo("Jane"); } @Test public void deleteRowsWithMixedClustering() throws IOException { setupMixedClusteringTestCase(); String body = RestUtils.get( authToken, String.format("%s:8082/v2/keyspaces/%s/%s/1/one/-1", host, keyspaceName, tableName), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(2); assertThat(data.get(0).get("v")).isEqualTo(9); assertThat(data.get(1).get("v")).isEqualTo(19); RestUtils.delete( authToken, String.format("%s:8082/v2/keyspaces/%s/%s/1/one/-1", host, keyspaceName, tableName), HttpStatus.SC_NO_CONTENT); body = RestUtils.get( authToken, String.format("%s:8082/v2/keyspaces/%s/%s/1/one/-1", host, keyspaceName, tableName), HttpStatus.SC_OK); getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); assertThat(getResponseWrapper.getCount()).isEqualTo(0); } @Test public void deleteRowsMixedClusteringAndCK() throws IOException { setupMixedClusteringTestCase(); String body = RestUtils.get( authToken, String.format("%s:8082/v2/keyspaces/%s/%s/1/one/-1", host, keyspaceName, tableName), HttpStatus.SC_OK); ListOfMapsGetResponseWrapper getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); List> data = getResponseWrapper.getData(); assertThat(getResponseWrapper.getCount()).isEqualTo(2); assertThat(data.get(0).get("v")).isEqualTo(9); assertThat(data.get(1).get("v")).isEqualTo(19); RestUtils.delete( authToken, String.format("%s:8082/v2/keyspaces/%s/%s/1/one/-1/20", host, keyspaceName, tableName), HttpStatus.SC_NO_CONTENT); body = RestUtils.get( authToken, String.format("%s:8082/v2/keyspaces/%s/%s/1/one/-1/20", host, keyspaceName, tableName), HttpStatus.SC_OK); getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); assertThat(getResponseWrapper.getCount()).isEqualTo(0); body = RestUtils.get( authToken, String.format("%s:8082/v2/keyspaces/%s/%s/1/one/-1", host, keyspaceName, tableName), HttpStatus.SC_OK); getResponseWrapper = LIST_OF_MAPS_GETRESPONSE_READER.readValue(body); assertThat(getResponseWrapper.getCount()).isEqualTo(1); assertThat(data.get(0).get("v")).isEqualTo(9); } @Test public void deleteRowNoSuchKey() throws IOException { createTestKeyspace(keyspaceName); createTestTable(keyspaceName, tableName); // First, try deleting row with valid UUID but one for which there is no row // We should just get usual "NO_CONTENT" as DELETE is idempotent final String rowIdentifier = UUID.randomUUID().toString(); RestUtils.delete( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, rowIdentifier), HttpStatus.SC_NO_CONTENT); // But then see what happens with invalid key (String that is not UUID, in this case) RestUtils.delete( authToken, String.format( "%s:8082/v2/keyspaces/%s/%s/%s", host, keyspaceName, tableName, "not-really-an-uuid"), HttpStatus.SC_BAD_REQUEST); } /* /************************************************************************ /* Helper methods for setting up tests /************************************************************************ */ private void createTestTable(String keyspaceName, String tableName) throws IOException { TableAdd tableAdd = new TableAdd(); tableAdd.setName(tableName); List columnDefinitions = new ArrayList<>(); columnDefinitions.add(new ColumnDefinition("id", "uuid")); columnDefinitions.add(new ColumnDefinition("lastName", "text")); columnDefinitions.add(new ColumnDefinition("firstName", "text")); columnDefinitions.add(new ColumnDefinition("age", "int")); tableAdd.setColumnDefinitions(columnDefinitions); PrimaryKey primaryKey = new PrimaryKey(); primaryKey.setPartitionKey(Collections.singletonList("id")); tableAdd.setPrimaryKey(primaryKey); RestUtils.post( authToken, String.format("%s/v2/schemas/keyspaces/%s/tables", restUrlBase, keyspaceName), objectMapper.writeValueAsString(tableAdd), HttpStatus.SC_CREATED); } private void createTestTable( String tableName, List columns, List partitionKey, List clusteringKey) throws IOException { TableAdd tableAdd = new TableAdd(); tableAdd.setName(tableName); List columnDefinitions = columns.stream() .map(x -> x.split(" ")) .map(y -> new ColumnDefinition(y[0], y[1])) .collect(Collectors.toList()); tableAdd.setColumnDefinitions(columnDefinitions); PrimaryKey primaryKey = new PrimaryKey(); primaryKey.setPartitionKey(partitionKey); if (clusteringKey != null) { primaryKey.setClusteringKey(clusteringKey); } tableAdd.setPrimaryKey(primaryKey); String body = RestUtils.post( authToken, String.format("%s/v2/schemas/keyspaces/%s/tables", restUrlBase, keyspaceName), objectMapper.writeValueAsString(tableAdd), HttpStatus.SC_CREATED); TableResponse tableResponse = objectMapper.readValue(body, TableResponse.class); assertThat(tableResponse.getName()).isEqualTo(tableName); } private void createTestTableWithClustering(String keyspaceName, String tableName) throws IOException { TableAdd tableAdd = new TableAdd(); tableAdd.setName(tableName); List columnDefinitions = new ArrayList<>(); columnDefinitions.add(new ColumnDefinition("id", "int")); columnDefinitions.add(new ColumnDefinition("lastName", "text")); columnDefinitions.add(new ColumnDefinition("firstName", "text")); columnDefinitions.add(new ColumnDefinition("age", "int", true)); columnDefinitions.add(new ColumnDefinition("expense_id", "int")); tableAdd.setColumnDefinitions(columnDefinitions); PrimaryKey primaryKey = new PrimaryKey(); primaryKey.setPartitionKey(Collections.singletonList("id")); primaryKey.setClusteringKey(Collections.singletonList("expense_id")); tableAdd.setPrimaryKey(primaryKey); RestUtils.post( authToken, String.format("%s/v2/schemas/keyspaces/%s/tables", restUrlBase, keyspaceName), objectMapper.writeValueAsString(tableAdd), HttpStatus.SC_CREATED); } private void createTestTableWithMixedClustering(String keyspaceName, String tableName) throws IOException { TableAdd tableAdd = new TableAdd(); tableAdd.setName(tableName); List columnDefinitions = new ArrayList<>(); columnDefinitions.add(new ColumnDefinition("pk0", "int")); columnDefinitions.add(new ColumnDefinition("pk1", "text")); columnDefinitions.add(new ColumnDefinition("pk2", "int")); columnDefinitions.add(new ColumnDefinition("ck0", "int")); columnDefinitions.add(new ColumnDefinition("ck1", "text")); columnDefinitions.add(new ColumnDefinition("v", "int")); tableAdd.setColumnDefinitions(columnDefinitions); PrimaryKey primaryKey = new PrimaryKey(); primaryKey.setPartitionKey(Arrays.asList("pk0", "pk1", "pk2")); primaryKey.setClusteringKey(Arrays.asList("ck0", "ck1")); tableAdd.setPrimaryKey(primaryKey); RestUtils.post( authToken, String.format("%s/v2/schemas/keyspaces/%s/tables", restUrlBase, keyspaceName), objectMapper.writeValueAsString(tableAdd), HttpStatus.SC_CREATED); } private void createTestKeyspace(String keyspaceName) throws IOException { String createKeyspaceRequest = String.format("{\"name\": \"%s\", \"replicas\": 1}", keyspaceName); RestUtils.post( authToken, String.format("%s/v2/schemas/keyspaces", restUrlBase), createKeyspaceRequest, HttpStatus.SC_CREATED); } private void createTestIndex( String keyspaceName, String tableName, String columnName, String indexName, boolean ifNotExists, IndexKind kind) throws IOException { IndexAdd indexAdd = new IndexAdd(); indexAdd.setColumn(columnName); indexAdd.setName(indexName); indexAdd.setIfNotExists(ifNotExists); indexAdd.setKind(kind); String body = RestUtils.post( authToken, String.format( "%s/v2/schemas/keyspaces/%s/tables/%s/indexes", restUrlBase, keyspaceName, tableName), objectMapper.writeValueAsString(indexAdd), HttpStatus.SC_CREATED); SuccessResponse successResponse = objectMapper.readValue(body, SuccessResponse.class); assertThat(successResponse.getSuccess()).isTrue(); } /** * Helper method for inserting table entries using so-called "Stringified" values for columns: * this differs a bit from full JSON values and is mostly useful for simple String and number * fields. * * @return {@code List} of entries to expect back for given definitions. */ private List> insertTestTableRows(List> rows) throws IOException { final List> insertedRows = new ArrayList<>(); for (List row : rows) { Map rowMap = new HashMap<>(); for (String kv : row) { // Split on first space, leave others in (with no limit we'd silently // drop later space-separated parts) String[] parts = kv.split(" ", 2); rowMap.put(parts[0].trim(), parts[1].trim()); } insertedRows.add(rowMap); RestUtils.post( authToken, String.format("%s/v2/keyspaces/%s/%s", restUrlBase, keyspaceName, tableName), objectMapper.writeValueAsString(rowMap), HttpStatus.SC_CREATED); } return insertedRows; } // Variant of "insertTestTableRows" in which entries are defined as partially // typed Java Objects and serialized as real JSON and NOT as "Stringified" // CQL-style format. private void insertTypedTestTableRows(List> rows) throws IOException { for (Map row : rows) { RestUtils.post( authToken, String.format("%s/v2/keyspaces/%s/%s", restUrlBase, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); } } private String setupClusteringTestCase() throws IOException { createTestKeyspace(keyspaceName); createTestTableWithClustering(keyspaceName, tableName); String rowIdentifier = "1"; Map row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); row.put("expense_id", "1"); RestUtils.post( authToken, String.format("%s/v2/keyspaces/%s/%s", restUrlBase, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); row = new HashMap<>(); row.put("id", rowIdentifier); row.put("firstName", "John"); row.put("expense_id", "2"); RestUtils.post( authToken, String.format("%s/v2/keyspaces/%s/%s", restUrlBase, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); row = new HashMap<>(); row.put("id", "2"); row.put("firstName", "Jane"); row.put("expense_id", "1"); RestUtils.post( authToken, String.format("%s/v2/keyspaces/%s/%s", restUrlBase, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); row = new HashMap<>(); row.put("id", "2"); row.put("firstName", "Jane"); row.put("expense_id", "1"); RestUtils.post( authToken, String.format("%s/v2/keyspaces/%s/%s", restUrlBase, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); return rowIdentifier; } private void setupMixedClusteringTestCase() throws IOException { createTestKeyspace(keyspaceName); createTestTableWithMixedClustering(keyspaceName, tableName); Map row = new HashMap<>(); row.put("pk0", "1"); row.put("pk1", "one"); row.put("pk2", "-1"); row.put("ck0", "10"); row.put("ck1", "foo"); row.put("v", "9"); RestUtils.post( authToken, String.format("%s/v2/keyspaces/%s/%s", restUrlBase, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); row = new HashMap<>(); row.put("pk0", "1"); row.put("pk1", "one"); row.put("pk2", "-1"); row.put("ck0", "20"); row.put("ck1", "foo"); row.put("v", "19"); RestUtils.post( authToken, String.format("%s/v2/keyspaces/%s/%s", restUrlBase, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); row = new HashMap<>(); row.put("pk0", "2"); row.put("pk1", "two"); row.put("pk2", "-2"); row.put("ck0", "10"); row.put("ck1", "bar"); row.put("v", "18"); RestUtils.post( authToken, String.format("%s/v2/keyspaces/%s/%s", restUrlBase, keyspaceName, tableName), objectMapper.writeValueAsString(row), HttpStatus.SC_CREATED); } private T readWrappedRESTResponse(String body, Class wrappedType) throws IOException { JavaType wrapperType = objectMapper .getTypeFactory() .constructParametricType(RESTResponseWrapper.class, wrappedType); RESTResponseWrapper wrapped = objectMapper.readValue(body, wrapperType); return wrapped.getData(); } // Simple helper method for the case of single primary key, standard auth token; // will use "raw" Rows endpoint to access entries, return as Tree (JsonNode) private JsonNode readRawRowsBySingleKey(String keyspaceName, String tableName, Object rowId) throws IOException { String body = RestUtils.get( authToken, String.format( "%s/v2/keyspaces/%s/%s/%s?raw=true", restUrlBase, keyspaceName, tableName, rowId), HttpStatus.SC_OK); return objectMapper.readTree(body); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy