From badb3b2eca6bac9bf64abe29d56dc9a296a643b8 Mon Sep 17 00:00:00 2001 From: YuqiDu Date: Fri, 8 Mar 2024 08:00:00 -0800 Subject: [PATCH] Revert "remove some bridge related dependencies (#890)" This reverts commit 1e8570675e735742dcf90767e548a0d5d7a677af. --- docker-compose/docker-compose-dev-mode.yml | 3 +- docker-compose/docker-compose.yml | 3 +- helm/README.md | 13 ++- helm/jsonapi/Chart.yaml | 3 +- .../stargate_jsonapi_deployment.yaml | 78 ++++++++-------- helm/jsonapi/values.yaml | 18 ++-- ...sonapiRetriableStargateBridgeProvider.java | 21 +++++ .../sgv2/jsonapi/exception/ErrorCode.java | 4 + .../retries/impl/JsonApiGrpcRetryPolicy.java | 70 +++++++++++++++ .../operation/model/ReadOperation.java | 15 ++++ .../operation/model/impl/DBFilterBase.java | 21 +++++ .../impl/CreateCollectionCommandResolver.java | 12 ++- src/main/resources/application.yaml | 6 +- .../JsonApiGrpcRetryPolicyBridgeTest.java | 24 +++++ .../impl/JsonApiGrpcRetryPolicyTest.java | 89 +++++++++++++++++++ ...eCollectionResolverVectorDisabledTest.java | 53 +++++++++++ .../impl/DisableVectorSearchProfile.java | 19 ++++ 17 files changed, 395 insertions(+), 57 deletions(-) create mode 100644 src/main/java/io/stargate/sgv2/jsonapi/JsonapiRetriableStargateBridgeProvider.java create mode 100644 src/main/java/io/stargate/sgv2/jsonapi/grpc/retries/impl/JsonApiGrpcRetryPolicy.java create mode 100644 src/test/java/io/stargate/sgv2/jsonapi/grpc/retries/impl/JsonApiGrpcRetryPolicyBridgeTest.java create mode 100644 src/test/java/io/stargate/sgv2/jsonapi/grpc/retries/impl/JsonApiGrpcRetryPolicyTest.java create mode 100644 src/test/java/io/stargate/sgv2/jsonapi/service/resolver/model/impl/CreateCollectionResolverVectorDisabledTest.java create mode 100644 src/test/java/io/stargate/sgv2/jsonapi/service/resolver/model/impl/DisableVectorSearchProfile.java diff --git a/docker-compose/docker-compose-dev-mode.yml b/docker-compose/docker-compose-dev-mode.yml index 52436170a0..b5ccd73d24 100644 --- a/docker-compose/docker-compose-dev-mode.yml +++ b/docker-compose/docker-compose-dev-mode.yml @@ -36,7 +36,8 @@ services: - JAVA_MAX_MEM_RATIO=75 - JAVA_INITIAL_MEM_RATIO=50 - GC_CONTAINER_OPTIONS=-XX:+UseG1GC - - STARGATE_JSONAPI_OPERATIONS_DATABASE_CONFIG_CASSANDRA_END_POINTS=coordinator + - QUARKUS_GRPC_CLIENTS_BRIDGE_HOST=coordinator + - QUARKUS_GRPC_CLIENTS_BRIDGE_PORT=8091 - QUARKUS_HTTP_ACCESS_LOG_ENABLED=${REQUESTLOG} - QUARKUS_LOG_LEVEL=${LOGLEVEL} - JAVA_OPTS_APPEND=-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml index 76def4f23a..aaea210a03 100644 --- a/docker-compose/docker-compose.yml +++ b/docker-compose/docker-compose.yml @@ -71,7 +71,8 @@ services: - JAVA_MAX_MEM_RATIO=75 - JAVA_INITIAL_MEM_RATIO=50 - GC_CONTAINER_OPTIONS=-XX:+UseG1GC - - STARGATE_JSONAPI_OPERATIONS_DATABASE_CONFIG_CASSANDRA_END_POINTS=coordinator + - QUARKUS_GRPC_CLIENTS_BRIDGE_HOST=coordinator + - QUARKUS_GRPC_CLIENTS_BRIDGE_PORT=8091 - QUARKUS_HTTP_ACCESS_LOG_ENABLED=${REQUESTLOG} - QUARKUS_LOG_LEVEL=${LOGLEVEL} - JAVA_OPTS_APPEND=-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager diff --git a/helm/README.md b/helm/README.md index ba3b372b5f..acd54d69a0 100644 --- a/helm/README.md +++ b/helm/README.md @@ -1,10 +1,12 @@ # Stargate JSON API deployment using Helm ## Pre-requisites -### Stargate Coordinator Instance -You'll need the Stargate Coordinator instance deployed with port 9042 accessible -You can deploy the stargate coordinator node using the helm setup at https://github.com/stargate/stargate/tree/main/helm +### Stargate GRPC Bridge Instance +You'll need the Stargate Bridge instance deployed with port 8091 accessible + +#### Stargate GRPC Bridge Setup +You can deploy the stargate bridge / coordinator node using the helm setup at https://github.com/stargate/stargate/tree/main/helm ### Autoscaling Autoscaling uses metrics server. Metrics server can be installed by executing the command: @@ -39,10 +41,13 @@ helm install jsonapi jsonapi ``` Note: -To install with override values, you can use the `--set` option as shown below: +- The default values in the Helm values file (`values.yaml`) are set to assume that Stargate GRPC Bridge is setup in `default` kubernetes namespace + +To install with overriden values, you can use the `--set` option as shown below: ```shell script helm install jsonapi jsonapi \ --namespace \ +--set sgGrpcBridge.namespace= \ --set replicaCount=2 ``` \ No newline at end of file diff --git a/helm/jsonapi/Chart.yaml b/helm/jsonapi/Chart.yaml index 139ffd8a76..d4537f3a2d 100644 --- a/helm/jsonapi/Chart.yaml +++ b/helm/jsonapi/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: jsonapi -description: A Helm chart to deploy stargate JSON API +description: A Helm chart to deploy stargate JSON API # A chart can be either an 'application' or a 'library' chart. # @@ -22,4 +22,3 @@ version: 0.1.0 # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. appVersion: "3.0.0" - diff --git a/helm/jsonapi/templates/stargate_jsonapi_deployment.yaml b/helm/jsonapi/templates/stargate_jsonapi_deployment.yaml index 83cc0ebaad..fd1e8d6657 100644 --- a/helm/jsonapi/templates/stargate_jsonapi_deployment.yaml +++ b/helm/jsonapi/templates/stargate_jsonapi_deployment.yaml @@ -18,41 +18,45 @@ spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: - app: stargate-jsonapi - topologyKey: {{ .Values.topologyKey }} + - labelSelector: + matchLabels: + app: stargate-jsonapi + topologyKey: {{ .Values.topologyKey }} + initContainers: + - name: wait-for-bridge + image: busybox + command: ["sh", "-c", "until nc -z {{ .Values.sgGrpcBridge.serviceName }}.{{ .Values.sgGrpcBridge.namespace }} 8091 > /dev/null; do echo Waiting for bridge.; sleep 5;done;"] containers: - - name: jsonapi - image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag }}" - ports: - - containerPort: 8181 - readinessProbe: - httpGet: - path: {{ .Values.probe.readiness.url }} - port: {{ .Values.probe.readiness.port }} - timeoutSeconds: {{ .Values.probe.readiness.timeoutSeconds }} - periodSeconds: {{ .Values.probe.readiness.periodSeconds }} - failureThreshold: {{ .Values.probe.readiness.failureThreshold }} - initialDelaySeconds: {{ .Values.probe.readiness.initialDelaySeconds }} - livenessProbe: - httpGet: - path: {{ .Values.probe.liveness.url }} - port: {{ .Values.probe.liveness.port }} - timeoutSeconds: {{ .Values.probe.liveness.timeoutSeconds }} - periodSeconds: {{ .Values.probe.liveness.periodSeconds }} - failureThreshold: {{ .Values.probe.liveness.failureThreshold }} - initialDelaySeconds: {{ .Values.probe.liveness.initialDelaySeconds }} - resources: - requests: - cpu: {{ .Values.cpu | default 1000 }}m - memory: {{ .Values.memory | default 1024 }}Mi - env: - - name: STARGATE_JSONAPI_OPERATIONS_DATABASE_CONFIG_CASSANDRA_END_POINTS - value: {{ .Values.cassandraEndPoints }} - - name: IO_STARGATE_SGV2_API_COMMON_PROPERTIES_DATASTORE_CONFIGURATION_DATASTOREPROPERTIESCONFIGURATION_FETCHSUPPORTEDFEATURES_RETRY_MAXRETRIES - value: "50" - - name: IO_STARGATE_SGV2_API_COMMON_PROPERTIES_DATASTORE_CONFIGURATION_DATASTOREPROPERTIESCONFIGURATION_FETCHSUPPORTEDFEATURES_RETRY_MAXDURATION - value: "300" - - name: IO_STARGATE_SGV2_API_COMMON_PROPERTIES_DATASTORE_CONFIGURATION_DATASTOREPROPERTIESCONFIGURATION_FETCHSUPPORTEDFEATURES_RETRY_DELAY - value: "10" + - name: jsonapi + image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag }}" + ports: + - containerPort: 8181 + readinessProbe: + httpGet: + path: {{ .Values.probe.readiness.url }} + port: {{ .Values.probe.readiness.port }} + timeoutSeconds: {{ .Values.probe.readiness.timeoutSeconds }} + periodSeconds: {{ .Values.probe.readiness.periodSeconds }} + failureThreshold: {{ .Values.probe.readiness.failureThreshold }} + initialDelaySeconds: {{ .Values.probe.readiness.initialDelaySeconds }} + livenessProbe: + httpGet: + path: {{ .Values.probe.liveness.url }} + port: {{ .Values.probe.liveness.port }} + timeoutSeconds: {{ .Values.probe.liveness.timeoutSeconds }} + periodSeconds: {{ .Values.probe.liveness.periodSeconds }} + failureThreshold: {{ .Values.probe.liveness.failureThreshold }} + initialDelaySeconds: {{ .Values.probe.liveness.initialDelaySeconds }} + resources: + requests: + cpu: {{ .Values.cpu | default 1000 }}m + memory: {{ .Values.memory | default 1024 }}Mi + env: + - name: QUARKUS_GRPC_CLIENTS_BRIDGE_HOST + value: "{{ .Values.sgGrpcBridge.serviceName }}.{{ .Values.sgGrpcBridge.namespace }}" + - name: IO_STARGATE_SGV2_API_COMMON_PROPERTIES_DATASTORE_CONFIGURATION_DATASTOREPROPERTIESCONFIGURATION_FETCHSUPPORTEDFEATURES_RETRY_MAXRETRIES + value: "50" + - name: IO_STARGATE_SGV2_API_COMMON_PROPERTIES_DATASTORE_CONFIGURATION_DATASTOREPROPERTIESCONFIGURATION_FETCHSUPPORTEDFEATURES_RETRY_MAXDURATION + value: "300" + - name: IO_STARGATE_SGV2_API_COMMON_PROPERTIES_DATASTORE_CONFIGURATION_DATASTOREPROPERTIESCONFIGURATION_FETCHSUPPORTEDFEATURES_RETRY_DELAY + value: "10" diff --git a/helm/jsonapi/values.yaml b/helm/jsonapi/values.yaml index 6ee3c1baf0..37e43e0dc1 100644 --- a/helm/jsonapi/values.yaml +++ b/helm/jsonapi/values.yaml @@ -7,13 +7,18 @@ replicaCount: 1 # Coordinator or bridge registry and image image: - registry: "docker.io" + registry: "gcr.io" repository: "stargateio/jsonapi" tag: "v1" # topology key for anti affinity topologyKey: "kubernetes.io/hostname" +# Stargate gRPC bridge hostname and kubernetes namespace +sgGrpcBridge: + serviceName: "stargate-bridge" + namespace: "default" + # JSON API service image - don't change it. CPU and memory are both request cpu: 2000 memory: 2048 @@ -33,7 +38,7 @@ probe: failureThreshold: 5 initialDelaySeconds: 30 -# HorizontalPodAutoscaler for coordinator and all services. This needs metrics server installed (kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml) in the cluster. +# HorizontalPodAutoscaler for coordinator and all services. This needs metrics server installed (kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml) in the cluster. autoscaling: enabled: false minReplicas: 1 @@ -41,15 +46,12 @@ autoscaling: targetCPUUtilizationPercentage: 80 # targetMemoryUtilizationPercentage: 80 -# Ingress is not added to deployment by default. This needs to have ingress controller installed. Default configuration uses nginx controller. (Controller installed using -# helm upgrade --install ingress-nginx ingress-nginx \ +# Ingress is not added to deployment by default. This needs to have ingress controller installed. Default configuration uses nginx controller. (Controller installed using +# helm upgrade --install ingress-nginx ingress-nginx \ # --repo https://kubernetes.github.io/ingress-nginx \ # --namespace ingress-nginx --create-namespace -# To connect to cassandra, set ip for end points -cassandraEndPoints: "cassandra end points" - ingress: enabled: true ingressClassName: nginx - + diff --git a/src/main/java/io/stargate/sgv2/jsonapi/JsonapiRetriableStargateBridgeProvider.java b/src/main/java/io/stargate/sgv2/jsonapi/JsonapiRetriableStargateBridgeProvider.java new file mode 100644 index 0000000000..2cfb5836c3 --- /dev/null +++ b/src/main/java/io/stargate/sgv2/jsonapi/JsonapiRetriableStargateBridgeProvider.java @@ -0,0 +1,21 @@ +package io.stargate.sgv2.jsonapi; + +import io.quarkus.grpc.GrpcService; +import io.stargate.sgv2.api.common.grpc.qualifier.Retriable; +import jakarta.annotation.Priority; +import jakarta.enterprise.inject.Alternative; +import jakarta.inject.Singleton; +import jakarta.ws.rs.Produces; + +@Alternative +@Priority(1) +@GrpcService +@Singleton +public class JsonapiRetriableStargateBridgeProvider { + + @Produces + @Retriable + io.stargate.sgv2.api.common.grpc.RetriableStargateBridge retriableStargateBridge() { + return null; + } +} diff --git a/src/main/java/io/stargate/sgv2/jsonapi/exception/ErrorCode.java b/src/main/java/io/stargate/sgv2/jsonapi/exception/ErrorCode.java index 840cb8e4e2..d50a151c16 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/exception/ErrorCode.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/exception/ErrorCode.java @@ -118,6 +118,9 @@ public enum ErrorCode { UNSUPPORTED_UPDATE_FOR_VECTOR("Cannot use operator with '$vector' property"), UNSUPPORTED_UPDATE_FOR_VECTORIZE("Cannot use operator with '$vectorize' property"), + + VECTOR_SEARCH_NOT_AVAILABLE("Vector search functionality is not available in the backend"), + VECTOR_SEARCH_USAGE_ERROR("Vector search can't be used with other sort clause"), VECTOR_SEARCH_NOT_SUPPORTED("Vector search is not enabled for the collection "), @@ -132,6 +135,7 @@ public enum ErrorCode { VECTORIZE_SERVICE_TYPE_UNAVAILABLE("Vectorize service unavailable : "), VECTORIZE_USAGE_ERROR("Vectorize search can't be used with other sort clause"), + VECTORIZECONFIG_CHECK_FAIL("Internal server error: VectorizeConfig check fail"), UNAUTHENTICATED_REQUEST("UNAUTHENTICATED: Invalid token"), diff --git a/src/main/java/io/stargate/sgv2/jsonapi/grpc/retries/impl/JsonApiGrpcRetryPolicy.java b/src/main/java/io/stargate/sgv2/jsonapi/grpc/retries/impl/JsonApiGrpcRetryPolicy.java new file mode 100644 index 0000000000..4c3ddd78a5 --- /dev/null +++ b/src/main/java/io/stargate/sgv2/jsonapi/grpc/retries/impl/JsonApiGrpcRetryPolicy.java @@ -0,0 +1,70 @@ +package io.stargate.sgv2.jsonapi.grpc.retries.impl; + +import io.grpc.Metadata; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.grpc.protobuf.ProtoUtils; +import io.stargate.bridge.proto.QueryOuterClass; +import io.stargate.sgv2.api.common.grpc.retries.GrpcRetryPredicate; +import jakarta.enterprise.context.ApplicationScoped; +import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Default gRPC retry policy used in the project. The policy defines retries when: + * + *
    + *
  1. The received GRPC status code is UNAVAILABLE + *
  2. The received GRPC status code is DEADLINE_EXCEEDED, but the metadata received + * contains the trailers set by the Bridge in case of a server-side read, write and CAS write + * timeouts. + *
+ * + * Note that this class only defines the policy. Amount of retries and other retry properties are + * defined by stargate.grpc.retries property group. + */ +@ApplicationScoped +public class JsonApiGrpcRetryPolicy implements GrpcRetryPredicate { + private static final Logger logger = LoggerFactory.getLogger(JsonApiGrpcRetryPolicy.class); + private static final Metadata.Key WRITE_TIMEOUT_KEY = + ProtoUtils.keyForProto(QueryOuterClass.WriteTimeout.getDefaultInstance()); + + private static final Metadata.Key READ_TIMEOUT_KEY = + ProtoUtils.keyForProto(QueryOuterClass.ReadTimeout.getDefaultInstance()); + + /** {@inheritDoc} */ + @Override + public boolean test(StatusRuntimeException e) { + Status status = e.getStatus(); + Status.Code code = status.getCode(); + + // always retry unavailable + if (Objects.equals(code, Status.Code.UNAVAILABLE)) { + return true; + } + + // for timeouts, retry only server side timeouts + if (Objects.equals(code, Status.Code.DEADLINE_EXCEEDED)) { + return isValidServerSideTimeout(e.getTrailers()); + } + + // nothing else + return false; + } + + // ensure we retry only server side timeouts we want + private boolean isValidServerSideTimeout(Metadata trailers) { + // if we have trailers + if (null != trailers) { + // read, write and CAS write timeouts will include one of two trailers + if (trailers.containsKey(READ_TIMEOUT_KEY) || trailers.containsKey(WRITE_TIMEOUT_KEY)) { + logger.warn("DEADLINE_EXCEEDED with read/write timeout trailers, retrying"); + return true; + } + } + + // otherwise not + return false; + } +} diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/operation/model/ReadOperation.java b/src/main/java/io/stargate/sgv2/jsonapi/service/operation/model/ReadOperation.java index a101482aff..a13aad84af 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/operation/model/ReadOperation.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/operation/model/ReadOperation.java @@ -11,6 +11,8 @@ import com.google.common.collect.MinMaxPriorityQueue; import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.Uni; +import io.stargate.bridge.grpc.Values; +import io.stargate.bridge.proto.QueryOuterClass; import io.stargate.sgv2.jsonapi.api.v1.metrics.JsonProcessingMetricsReporter; import io.stargate.sgv2.jsonapi.exception.ErrorCode; import io.stargate.sgv2.jsonapi.exception.JsonApiException; @@ -333,6 +335,19 @@ default Uni findOrderDocument( }); } + /** + * Database key type is tuple, first field is json value type and second field is text + * + * @param value + * @return + */ + default DocumentId getDocumentId(QueryOuterClass.Value value) { + QueryOuterClass.Collection coll = value.getCollection(); + int typeId = Values.tinyint(coll.getElements(0)); + String documentIdAsText = Values.string(coll.getElements(1)); + return DocumentId.fromDatabase(typeId, documentIdAsText); + } + default DocumentId getDocumentId(TupleValue value) { int typeId = value.get(0, Byte.class); String documentIdAsText = value.get(1, String.class); diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/operation/model/impl/DBFilterBase.java b/src/main/java/io/stargate/sgv2/jsonapi/service/operation/model/impl/DBFilterBase.java index 05d8595409..a11176dc88 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/operation/model/impl/DBFilterBase.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/operation/model/impl/DBFilterBase.java @@ -7,11 +7,13 @@ import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import io.stargate.bridge.grpc.Values; +import io.stargate.bridge.proto.QueryOuterClass; import io.stargate.sgv2.api.common.cql.builder.BuiltCondition; import io.stargate.sgv2.api.common.cql.builder.Predicate; import io.stargate.sgv2.jsonapi.exception.ErrorCode; import io.stargate.sgv2.jsonapi.exception.JsonApiException; import io.stargate.sgv2.jsonapi.service.cqldriver.serializer.CQLBindValues; +import io.stargate.sgv2.jsonapi.service.cqldriver.serializer.CustomValueSerializers; import io.stargate.sgv2.jsonapi.service.shredding.model.DocValueHasher; import io.stargate.sgv2.jsonapi.service.shredding.model.DocumentId; import io.stargate.sgv2.jsonapi.util.JsonUtil; @@ -700,6 +702,21 @@ boolean canAddField() { } } + private static QueryOuterClass.Value getGrpcValue(Object value) { + if (value instanceof String) { + return Values.of((String) value); + } else if (value instanceof BigDecimal) { + return Values.of((BigDecimal) value); + } else if (value instanceof Byte) { + return Values.of((Byte) value); + } else if (value instanceof Integer) { + return Values.of((Integer) value); + } else if (value instanceof Date) { + return Values.of(((Date) value).getTime()); + } + return Values.of((String) null); + } + /** * Return JsonNode for a filter conditions value, used to set in new document created for upsert. * @@ -748,4 +765,8 @@ private static String getHashValue(DocValueHasher hasher, String path, Object ar private static String getHash(DocValueHasher hasher, Object arrayValue) { return hasher.getHash(arrayValue).hash(); } + + private static QueryOuterClass.Value getDocumentIdValue(DocumentId value) { + return Values.of(CustomValueSerializers.getDocumentIdValue(value)); + } } diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/model/impl/CreateCollectionCommandResolver.java b/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/model/impl/CreateCollectionCommandResolver.java index 54f9c84b04..46bc437698 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/model/impl/CreateCollectionCommandResolver.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/model/impl/CreateCollectionCommandResolver.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import io.stargate.sgv2.api.common.config.DataStoreConfig; import io.stargate.sgv2.jsonapi.api.model.command.CommandContext; import io.stargate.sgv2.jsonapi.api.model.command.impl.CreateCollectionCommand; import io.stargate.sgv2.jsonapi.config.DatabaseLimitsConfig; @@ -21,6 +22,8 @@ public class CreateCollectionCommandResolver implements CommandResolver documentLimitsConfig.maxVectorEmbeddingLength()) { diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 9f7e9c058a..47a43d0a06 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -3,6 +3,9 @@ stargate: + data-store: + ignore-bridge: true + database: limits: max-collections: 5 @@ -89,9 +92,6 @@ quarkus: port: 8181 - log: - min-level: trace - # built-in micrometer properties micrometer: binder: diff --git a/src/test/java/io/stargate/sgv2/jsonapi/grpc/retries/impl/JsonApiGrpcRetryPolicyBridgeTest.java b/src/test/java/io/stargate/sgv2/jsonapi/grpc/retries/impl/JsonApiGrpcRetryPolicyBridgeTest.java new file mode 100644 index 0000000000..e0711fdef9 --- /dev/null +++ b/src/test/java/io/stargate/sgv2/jsonapi/grpc/retries/impl/JsonApiGrpcRetryPolicyBridgeTest.java @@ -0,0 +1,24 @@ +package io.stargate.sgv2.jsonapi.grpc.retries.impl; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import io.stargate.sgv2.api.common.grpc.RetriableStargateBridge; +import io.stargate.sgv2.api.common.grpc.qualifier.Retriable; +import io.stargate.sgv2.common.bridge.BridgeTest; +import io.stargate.sgv2.common.testprofiles.NoGlobalResourcesTestProfile; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@TestProfile(NoGlobalResourcesTestProfile.Impl.class) +class JsonApiGrpcRetryPolicyBridgeTest extends BridgeTest { + + @Retriable @Inject RetriableStargateBridge bridge; + + @Test + public void checkForNull() { + assertThat(bridge).isNull(); + } +} diff --git a/src/test/java/io/stargate/sgv2/jsonapi/grpc/retries/impl/JsonApiGrpcRetryPolicyTest.java b/src/test/java/io/stargate/sgv2/jsonapi/grpc/retries/impl/JsonApiGrpcRetryPolicyTest.java new file mode 100644 index 0000000000..663818ad68 --- /dev/null +++ b/src/test/java/io/stargate/sgv2/jsonapi/grpc/retries/impl/JsonApiGrpcRetryPolicyTest.java @@ -0,0 +1,89 @@ +package io.stargate.sgv2.jsonapi.grpc.retries.impl; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.grpc.Metadata; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.grpc.protobuf.ProtoUtils; +import io.stargate.bridge.proto.QueryOuterClass; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class JsonApiGrpcRetryPolicyTest { + + JsonApiGrpcRetryPolicy policy = new JsonApiGrpcRetryPolicy(); + + @Nested + class PredicateTest { + + @Test + public void unavailable() { + StatusRuntimeException e = new StatusRuntimeException(Status.UNAVAILABLE); + + boolean result = policy.test(e); + + assertThat(result).isTrue(); + } + + @Test + public void deadlineWithReadTimeout() { + Metadata.Key key = + ProtoUtils.keyForProto(QueryOuterClass.ReadTimeout.getDefaultInstance()); + QueryOuterClass.ReadTimeout value = QueryOuterClass.ReadTimeout.newBuilder().build(); + Metadata metadata = new Metadata(); + metadata.put(key, value); + StatusRuntimeException e = new StatusRuntimeException(Status.DEADLINE_EXCEEDED, metadata); + + boolean result = policy.test(e); + + assertThat(result).isTrue(); + } + + @Test + public void deadlineWithWriteTimeout() { + Metadata.Key key = + ProtoUtils.keyForProto(QueryOuterClass.WriteTimeout.getDefaultInstance()); + QueryOuterClass.WriteTimeout value = QueryOuterClass.WriteTimeout.newBuilder().build(); + Metadata metadata = new Metadata(); + metadata.put(key, value); + StatusRuntimeException e = new StatusRuntimeException(Status.DEADLINE_EXCEEDED, metadata); + + boolean result = policy.test(e); + + assertThat(result).isTrue(); + } + + @Test + public void deadlineWithWrongTrailer() { + Metadata.Key key = + ProtoUtils.keyForProto(QueryOuterClass.Unavailable.getDefaultInstance()); + QueryOuterClass.Unavailable value = QueryOuterClass.Unavailable.newBuilder().build(); + Metadata metadata = new Metadata(); + metadata.put(key, value); + StatusRuntimeException e = new StatusRuntimeException(Status.DEADLINE_EXCEEDED, metadata); + + boolean result = policy.test(e); + + assertThat(result).isFalse(); + } + + @Test + public void deadlineWithoutTrailer() { + StatusRuntimeException e = new StatusRuntimeException(Status.DEADLINE_EXCEEDED); + + boolean result = policy.test(e); + + assertThat(result).isFalse(); + } + + @Test + public void ignoredStatusCode() { + StatusRuntimeException e = new StatusRuntimeException(Status.INTERNAL); + + boolean result = policy.test(e); + + assertThat(result).isFalse(); + } + } +} diff --git a/src/test/java/io/stargate/sgv2/jsonapi/service/resolver/model/impl/CreateCollectionResolverVectorDisabledTest.java b/src/test/java/io/stargate/sgv2/jsonapi/service/resolver/model/impl/CreateCollectionResolverVectorDisabledTest.java new file mode 100644 index 0000000000..59843ad7dd --- /dev/null +++ b/src/test/java/io/stargate/sgv2/jsonapi/service/resolver/model/impl/CreateCollectionResolverVectorDisabledTest.java @@ -0,0 +1,53 @@ +package io.stargate.sgv2.jsonapi.service.resolver.model.impl; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchException; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.quarkus.test.Mock; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import io.stargate.sgv2.jsonapi.api.model.command.CommandContext; +import io.stargate.sgv2.jsonapi.api.model.command.impl.CreateCollectionCommand; +import io.stargate.sgv2.jsonapi.exception.ErrorCode; +import io.stargate.sgv2.jsonapi.exception.JsonApiException; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@TestProfile(DisableVectorSearchProfile.class) +public class CreateCollectionResolverVectorDisabledTest { + @Inject ObjectMapper objectMapper; + @Inject CreateCollectionCommandResolver resolver; + + @Nested + class ResolveCommand { + + @Mock CommandContext commandContext; + + @Test + public void vectorSearchDisabled() throws Exception { + String json = + """ + { + "createCollection": { + "name" : "my_collection", + "options": { + "vector": { + "dimension": 4, + "metric": "cosine" + } + } + } + } + """; + + CreateCollectionCommand command = objectMapper.readValue(json, CreateCollectionCommand.class); + Exception e = catchException(() -> resolver.resolveCommand(commandContext, command)); + assertThat(e) + .isInstanceOf(JsonApiException.class) + .hasMessageStartingWith(ErrorCode.VECTOR_SEARCH_NOT_AVAILABLE.getMessage()); + } + } +} diff --git a/src/test/java/io/stargate/sgv2/jsonapi/service/resolver/model/impl/DisableVectorSearchProfile.java b/src/test/java/io/stargate/sgv2/jsonapi/service/resolver/model/impl/DisableVectorSearchProfile.java new file mode 100644 index 0000000000..936d136c67 --- /dev/null +++ b/src/test/java/io/stargate/sgv2/jsonapi/service/resolver/model/impl/DisableVectorSearchProfile.java @@ -0,0 +1,19 @@ +package io.stargate.sgv2.jsonapi.service.resolver.model.impl; + +import com.google.common.collect.ImmutableMap; +import io.quarkus.test.junit.QuarkusTestProfile; +import java.util.Map; + +public class DisableVectorSearchProfile implements QuarkusTestProfile { + @Override + public boolean disableGlobalTestResources() { + return true; + } + + @Override + public Map getConfigOverrides() { + return ImmutableMap.builder() + .put("stargate.data-store.vector-search-enabled", "false") + .build(); + } +}