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

io.stargate.it.http.docsapi.JsonSchemaResourceIntTest Maven / Gradle / Ivy

There is a newer version: 2.1.0-BETA-19
Show newest version
package io.stargate.it.http.docsapi;

import static org.assertj.core.api.Assertions.assertThat;

import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.shaded.guava.common.io.Resources;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
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.driver.TestKeyspace;
import io.stargate.it.http.RestUtils;
import io.stargate.it.http.models.Credentials;
import io.stargate.it.storage.StargateConnectionInfo;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import net.jcip.annotations.NotThreadSafe;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

@NotThreadSafe
public class JsonSchemaResourceIntTest extends BaseIntegrationTest {

  private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
  private static final OkHttpClient CLIENT =
      new OkHttpClient().newBuilder().readTimeout(Duration.ofMinutes(3)).build();

  private static String authToken;
  private static String host;
  private static String hostWithPort;

  @BeforeAll
  public static void setup(StargateConnectionInfo cluster) throws IOException {
    host = "http://" + cluster.seedAddress();
    hostWithPort = host + ":8082";

    initAuth();
  }

  private static void initAuth() throws IOException {
    OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    RequestBody requestBody =
        RequestBody.create(
            MediaType.parse("application/json"),
            OBJECT_MAPPER.writeValueAsString(new Credentials("cassandra", "cassandra")));

    Request request =
        new Request.Builder()
            .url(String.format("%s:8081/v1/auth/token/generate", host))
            .post(requestBody)
            .addHeader("X-Cassandra-Request-Id", "foo")
            .build();
    Response response = CLIENT.newCall(request).execute();
    ResponseBody body = response.body();

    assertThat(body).isNotNull();
    AuthTokenResponse authTokenResponse =
        OBJECT_MAPPER.readValue(body.string(), AuthTokenResponse.class);
    authToken = authTokenResponse.getAuthToken();
    assertThat(authToken).isNotNull();
  }

  String getCollectionPath(CqlIdentifier keyspace) {
    return hostWithPort + "/v2/namespaces/" + keyspace + "/collections";
  }

  String getSchemaPath(CqlIdentifier keyspace, String collectionName) {
    return getCollectionPath(keyspace) + "/" + collectionName + "/json-schema";
  }

  @Nested
  @CqlSessionSpec
  @ExtendWith(CqlSessionExtension.class)
  class GetJsonSchema {

    @Test
    public void schemaNotSet(@TestKeyspace CqlIdentifier keyspace) throws IOException {
      String collectionName = RandomStringUtils.randomAlphanumeric(10);
      RestUtils.post(
          authToken,
          getCollectionPath(keyspace),
          String.format("{\"name\":\"%s\"}", collectionName),
          201);

      String r = RestUtils.get(authToken, getSchemaPath(keyspace, collectionName), 404);

      assertThat(r)
          .isEqualTo(
              "{\"description\":\"The JSON schema is not set for the collection.\",\"code\":404}");
    }

    @Test
    public void notExistingCollection(@TestKeyspace CqlIdentifier keyspace) throws IOException {
      String r = RestUtils.get(authToken, getSchemaPath(keyspace, "not-existing"), 404);

      assertThat(r)
          .isEqualTo("{\"description\":\"Collection not-existing does not exist.\",\"code\":404}");
    }
  }

  @Nested
  @CqlSessionSpec
  @ExtendWith(CqlSessionExtension.class)
  class AttachJsonSchema {

    @Test
    public void happyPath(@TestKeyspace CqlIdentifier keyspace) throws IOException {
      String collectionName = RandomStringUtils.randomAlphanumeric(10);
      RestUtils.post(
          authToken,
          getCollectionPath(keyspace),
          String.format("{\"name\":\"%s\"}", collectionName),
          201);

      URL schema = this.getClass().getClassLoader().getResource("schema.json");
      String body = Resources.toString(schema, StandardCharsets.UTF_8);
      RestUtils.put(authToken, getSchemaPath(keyspace, collectionName), body, 200);

      String r = RestUtils.get(authToken, getSchemaPath(keyspace, collectionName), 200);
      assertThat(OBJECT_MAPPER.readTree(r).requiredAt("/schema"))
          .isEqualTo(OBJECT_MAPPER.readTree(body));

      // test valid doc insert, update and batch
      String validDoc = "{\"id\":1, \"name\":\"a\", \"price\":1}";
      RestUtils.post(authToken, getCollectionPath(keyspace) + "/" + collectionName, validDoc, 201);
      RestUtils.put(
          authToken, getCollectionPath(keyspace) + "/" + collectionName + "/1", validDoc, 200);
      RestUtils.post(
          authToken,
          getCollectionPath(keyspace) + "/" + collectionName + "/batch",
          String.format("[%s,%s]", validDoc, validDoc),
          202);

      // test invalid doc insert, update and batch
      String invalidDoc = "{\"id\":1, \"price\":1}";
      String insertResult =
          RestUtils.post(
              authToken, getCollectionPath(keyspace) + "/" + collectionName, invalidDoc, 400);
      String updateResult =
          RestUtils.put(
              authToken,
              getCollectionPath(keyspace) + "/" + collectionName + "/1",
              invalidDoc,
              400);
      String batchResult =
          RestUtils.post(
              authToken,
              getCollectionPath(keyspace) + "/" + collectionName + "/batch",
              String.format("[%s,%s]", validDoc, invalidDoc),
              400);

      assertThat(insertResult)
          .isEqualTo(updateResult)
          .isEqualTo(batchResult)
          .isEqualTo(
              "{\"description\":\"Invalid JSON: [object has missing required properties ([\\\"name\\\"])]\",\"code\":400}");
    }

    @Test
    public void partialUpdatesNotAllowed(@TestKeyspace CqlIdentifier keyspace) throws IOException {
      String collectionName = RandomStringUtils.randomAlphanumeric(10);
      RestUtils.post(
          authToken,
          getCollectionPath(keyspace),
          String.format("{\"name\":\"%s\"}", collectionName),
          201);

      URL schema = this.getClass().getClassLoader().getResource("schema.json");
      String body = Resources.toString(schema, StandardCharsets.UTF_8);
      RestUtils.put(authToken, getSchemaPath(keyspace, collectionName), body, 200);

      String doc = "{\"id\":1, \"name\":\"a\", \"price\":1}";

      // partial updates not allowed
      String updateResult =
          RestUtils.put(
              authToken, getCollectionPath(keyspace) + "/" + collectionName + "/1/path", doc, 400);

      String patchRootResult =
          RestUtils.patch(
              authToken, getCollectionPath(keyspace) + "/" + collectionName + "/1", doc, 400);

      String patchPathResult =
          RestUtils.patch(
              authToken, getCollectionPath(keyspace) + "/" + collectionName + "/1/path", doc, 400);

      assertThat(updateResult)
          .isEqualTo(patchRootResult)
          .isEqualTo(patchPathResult)
          .isEqualTo(
              "{\"description\":\"When a collection has a JSON schema, partial updates of documents are disallowed for performance reasons.\",\"code\":400}");
    }

    @Test
    public void invalidSchema(@TestKeyspace CqlIdentifier keyspace) throws IOException {
      String collectionName = RandomStringUtils.randomAlphanumeric(10);
      RestUtils.post(
          authToken,
          getCollectionPath(keyspace),
          String.format("{\"name\":\"%s\"}", collectionName),
          201);

      URL invalidSchema = this.getClass().getClassLoader().getResource("invalid-schema.json");
      String body = Resources.toString(invalidSchema, StandardCharsets.UTF_8);
      String r = RestUtils.put(authToken, getSchemaPath(keyspace, collectionName), body, 400);

      assertThat(r)
          .isEqualTo(
              "{\"description\":\"The provided JSON schema is invalid or malformed.\",\"code\":400}");
    }

    @Test
    public void notExistingCollection(@TestKeyspace CqlIdentifier keyspace) throws IOException {
      URL invalidSchema = this.getClass().getClassLoader().getResource("invalid-schema.json");
      String body = Resources.toString(invalidSchema, StandardCharsets.UTF_8);
      String r = RestUtils.put(authToken, getSchemaPath(keyspace, "not-existing"), body, 404);

      assertThat(r)
          .isEqualTo("{\"description\":\"Collection not-existing does not exist.\",\"code\":404}");
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy