From c56ccada38fb15eca0c572814e3164ad5afb94d3 Mon Sep 17 00:00:00 2001 From: Aaron Steinfeld <45047841+aaron-steinfeld@users.noreply.github.com> Date: Fri, 1 Oct 2021 08:05:58 -0700 Subject: [PATCH] style: add spotless (#88) * style: add spotless * chore: fix snyk --- README.md | 6 +- build.gradle.kts | 2 + query-service-api/build.gradle.kts | 7 +- .../src/main/proto/request.proto | 2 - .../src/main/proto/response.proto | 1 - .../query/service/api/QueryRequestTest.java | 40 +- query-service-impl/build.gradle.kts | 4 +- .../core/query/service/ExecutionContext.java | 4 +- .../query/service/QueryFunctionConstants.java | 1 - .../query/service/QueryTransformation.java | 3 +- .../query/service/RequestHandlerInfo.java | 4 +- .../core/query/service/pinot/Params.java | 26 +- .../pinot/PinotBasedRequestHandler.java | 8 +- .../service/pinot/PinotClientFactory.java | 6 +- .../core/query/service/pinot/PinotModule.java | 2 +- .../pinot/PinotRequestHandlerBuilder.java | 2 +- .../QueryRequestToPinotSQLConverter.java | 17 +- .../query/service/pinot/ViewColumnFilter.java | 20 +- .../DestinationColumnValueConverter.java | 21 +- .../query/service/QueryServiceConfigTest.java | 4 +- .../DestinationColumnValueConverterTest.java | 8 +- .../core/query/service/pinot/ParamsTest.java | 24 +- .../pinot/PinotBasedRequestHandlerTest.java | 1139 +++++++++++------ .../query/service/pinot/PinotQueryTest.java | 15 +- .../pinot/PinotResultAnalyzerTest.java | 33 +- .../query/service/pinot/PinotUtilsTest.java | 12 +- .../QueryRequestToPinotSQLConverterTest.java | 246 ++-- .../ProjectionTransformationTest.java | 2 +- query-service/build.gradle.kts | 6 +- .../query/service/QueryServiceTestUtils.java | 8 +- .../service/htqueries/BackendsQueries.java | 68 +- .../service/htqueries/ExplorerQueries.java | 76 +- .../service/htqueries/HTPinotQueriesTest.java | 245 ++-- .../service/htqueries/ServicesQueries.java | 58 +- 34 files changed, 1276 insertions(+), 844 deletions(-) diff --git a/README.md b/README.md index b236f2a0..5920a949 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ The Query Service interfaces with Apache Pinot Data Store ## Description -| ![space-1.jpg](https://hypertrace-docs.s3.amazonaws.com/arch/ht-query.png) | -|:--:| +| ![space-1.jpg](https://hypertrace-docs.s3.amazonaws.com/arch/ht-query.png) | +|:--:| | *Hypertrace Query Architecture* | - Query Service serves time series data for attributes/metrics from spans and events. The query interface this exposes is more like a table where you can select any columns, aggregations on them with filters. It's easy to do slicing and dicing of data (only from one table since no JOINs are supported) with this interface. @@ -20,7 +20,7 @@ The Query service uses gradlew to compile/install/distribute. Gradle wrapper is ## Testing ### Running unit tests -Run `./gradlew test` to execute unit tests. +Run `./gradlew test` to execute unit tests. ### Testing image diff --git a/build.gradle.kts b/build.gradle.kts index 70561c04..680c96a5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,10 +4,12 @@ plugins { id("org.hypertrace.publish-plugin") version "1.0.2" apply false id("org.hypertrace.jacoco-report-plugin") version "0.2.0" apply false id("org.hypertrace.integration-test-plugin") version "0.2.0" apply false + id("org.hypertrace.code-style-plugin") version "1.1.1" apply false } subprojects { group = "org.hypertrace.core.query.service" + apply(plugin = "org.hypertrace.code-style-plugin") pluginManager.withPlugin("org.hypertrace.publish-plugin") { configure { license.set(org.hypertrace.gradle.publishing.License.TRACEABLE_COMMUNITY) diff --git a/query-service-api/build.gradle.kts b/query-service-api/build.gradle.kts index c56239f4..b9682a49 100644 --- a/query-service-api/build.gradle.kts +++ b/query-service-api/build.gradle.kts @@ -1,4 +1,9 @@ -import com.google.protobuf.gradle.* +import com.google.protobuf.gradle.generateProtoTasks +import com.google.protobuf.gradle.id +import com.google.protobuf.gradle.ofSourceSet +import com.google.protobuf.gradle.plugins +import com.google.protobuf.gradle.protobuf +import com.google.protobuf.gradle.protoc plugins { `java-library` diff --git a/query-service-api/src/main/proto/request.proto b/query-service-api/src/main/proto/request.proto index af963458..cf98278d 100644 --- a/query-service-api/src/main/proto/request.proto +++ b/query-service-api/src/main/proto/request.proto @@ -82,5 +82,3 @@ enum SortOrder { ASC = 0; DESC = 1; } - - diff --git a/query-service-api/src/main/proto/response.proto b/query-service-api/src/main/proto/response.proto index af59beaa..9e3e684e 100644 --- a/query-service-api/src/main/proto/response.proto +++ b/query-service-api/src/main/proto/response.proto @@ -35,4 +35,3 @@ message ResultSetChunk { message Row { repeated Value column = 1; } - diff --git a/query-service-api/src/test/java/org/hypertrace/core/query/service/api/QueryRequestTest.java b/query-service-api/src/test/java/org/hypertrace/core/query/service/api/QueryRequestTest.java index 494012ad..e8ae72ab 100644 --- a/query-service-api/src/test/java/org/hypertrace/core/query/service/api/QueryRequestTest.java +++ b/query-service-api/src/test/java/org/hypertrace/core/query/service/api/QueryRequestTest.java @@ -5,23 +5,35 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -/** - * Unit tests for {@link QueryRequest} - */ +/** Unit tests for {@link QueryRequest} */ public class QueryRequestTest { @Test public void testJsonSerializeDeserialize() throws InvalidProtocolBufferException { - QueryRequest.Builder builder = QueryRequest.newBuilder() - .addSelection(Expression.newBuilder().setColumnIdentifier( - ColumnIdentifier.newBuilder().setColumnName("test").setAlias("my_column").build())) - .addAggregation(Expression.newBuilder().setFunction( - Function.newBuilder().setFunctionName("SUM").build())) - .addGroupBy(Expression.newBuilder().setColumnIdentifier( - ColumnIdentifier.newBuilder().setColumnName("test").build())) - .addOrderBy(OrderByExpression.newBuilder().setOrderValue(-1).setExpression( - Expression.newBuilder().setColumnIdentifier( - ColumnIdentifier.newBuilder().setColumnName("column2")))) - .setOffset(0).setLimit(1); + QueryRequest.Builder builder = + QueryRequest.newBuilder() + .addSelection( + Expression.newBuilder() + .setColumnIdentifier( + ColumnIdentifier.newBuilder() + .setColumnName("test") + .setAlias("my_column") + .build())) + .addAggregation( + Expression.newBuilder() + .setFunction(Function.newBuilder().setFunctionName("SUM").build())) + .addGroupBy( + Expression.newBuilder() + .setColumnIdentifier( + ColumnIdentifier.newBuilder().setColumnName("test").build())) + .addOrderBy( + OrderByExpression.newBuilder() + .setOrderValue(-1) + .setExpression( + Expression.newBuilder() + .setColumnIdentifier( + ColumnIdentifier.newBuilder().setColumnName("column2")))) + .setOffset(0) + .setLimit(1); QueryRequest request = builder.build(); // Serialize into json. diff --git a/query-service-impl/build.gradle.kts b/query-service-impl/build.gradle.kts index 53b35757..015072cd 100644 --- a/query-service-impl/build.gradle.kts +++ b/query-service-impl/build.gradle.kts @@ -19,10 +19,10 @@ dependencies { implementation("org.apache.zookeeper:zookeeper:3.6.2") { because("Multiple vulnerabilities") } - implementation("io.netty:netty-transport-native-epoll:4.1.63.Final") { + implementation("io.netty:netty-transport-native-epoll:4.1.68.Final") { because("Multiple vulnerabilities") } - implementation("io.netty:netty-handler:4.1.63.Final") { + implementation("io.netty:netty-handler:4.1.68.Final") { because("Multiple vulnerabilities") } } diff --git a/query-service-impl/src/main/java/org/hypertrace/core/query/service/ExecutionContext.java b/query-service-impl/src/main/java/org/hypertrace/core/query/service/ExecutionContext.java index b3ec8c7d..40d54715 100644 --- a/query-service-impl/src/main/java/org/hypertrace/core/query/service/ExecutionContext.java +++ b/query-service-impl/src/main/java/org/hypertrace/core/query/service/ExecutionContext.java @@ -18,8 +18,8 @@ import org.hypertrace.core.query.service.api.ValueType; /** - * Wrapper class to hold the query execution context that is needed by different components - * during the life cycles of a request. + * Wrapper class to hold the query execution context that is needed by different components during + * the life cycles of a request. */ public class ExecutionContext { diff --git a/query-service-impl/src/main/java/org/hypertrace/core/query/service/QueryFunctionConstants.java b/query-service-impl/src/main/java/org/hypertrace/core/query/service/QueryFunctionConstants.java index 8ba5e5c9..4d0adb6e 100644 --- a/query-service-impl/src/main/java/org/hypertrace/core/query/service/QueryFunctionConstants.java +++ b/query-service-impl/src/main/java/org/hypertrace/core/query/service/QueryFunctionConstants.java @@ -1,6 +1,5 @@ package org.hypertrace.core.query.service; - /** * Canonical query function names received in requests. These should be converted to data-store * specific names when handling a request. diff --git a/query-service-impl/src/main/java/org/hypertrace/core/query/service/QueryTransformation.java b/query-service-impl/src/main/java/org/hypertrace/core/query/service/QueryTransformation.java index bfb3141f..09428e0f 100644 --- a/query-service-impl/src/main/java/org/hypertrace/core/query/service/QueryTransformation.java +++ b/query-service-impl/src/main/java/org/hypertrace/core/query/service/QueryTransformation.java @@ -4,7 +4,8 @@ import org.hypertrace.core.query.service.api.QueryRequest; public interface QueryTransformation { - Single transform(QueryRequest queryRequest, QueryTransformationContext transformationContext); + Single transform( + QueryRequest queryRequest, QueryTransformationContext transformationContext); interface QueryTransformationContext {} } diff --git a/query-service-impl/src/main/java/org/hypertrace/core/query/service/RequestHandlerInfo.java b/query-service-impl/src/main/java/org/hypertrace/core/query/service/RequestHandlerInfo.java index 6d9b4ecf..388ba565 100644 --- a/query-service-impl/src/main/java/org/hypertrace/core/query/service/RequestHandlerInfo.java +++ b/query-service-impl/src/main/java/org/hypertrace/core/query/service/RequestHandlerInfo.java @@ -11,9 +11,7 @@ public class RequestHandlerInfo { private final Config config; public RequestHandlerInfo( - String name, - Class requestHandlerClazz, - Config config) { + String name, Class requestHandlerClazz, Config config) { this.name = name; this.requestHandlerClazz = requestHandlerClazz; this.config = config; diff --git a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/Params.java b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/Params.java index eb7fa9ec..5fd21610 100644 --- a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/Params.java +++ b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/Params.java @@ -59,14 +59,20 @@ public Map getByteStringParams() { @Override public String toString() { - return "Params{" + - "integerParams=" + integerParams + - ", longParams=" + longParams + - ", stringParams=" + stringParams + - ", floatParams=" + floatParams + - ", doubleParams=" + doubleParams + - ", byteStringParams=" + byteStringParams + - '}'; + return "Params{" + + "integerParams=" + + integerParams + + ", longParams=" + + longParams + + ", stringParams=" + + stringParams + + ", floatParams=" + + floatParams + + ", doubleParams=" + + doubleParams + + ", byteStringParams=" + + byteStringParams + + '}'; } @Override @@ -164,8 +170,8 @@ public Builder addByteStringParam(ByteString paramValue) { } public Params build() { - return new Params(integerParams, longParams, stringParams, floatParams, doubleParams, - byteStringParams); + return new Params( + integerParams, longParams, stringParams, floatParams, doubleParams, byteStringParams); } } } diff --git a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotBasedRequestHandler.java b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotBasedRequestHandler.java index e887b7da..df2ec26e 100644 --- a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotBasedRequestHandler.java +++ b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotBasedRequestHandler.java @@ -173,10 +173,10 @@ public QueryCost canHandle(QueryRequest request, ExecutionContext executionConte return QueryCost.UNSUPPORTED; } -// TODO -// if (!this.viewDefinitionSupportsGranularity(viewDefinition, request.getGroupByList())) { -// return QueryCost.UNSUPPORTED; -// } + // TODO + // if (!this.viewDefinitionSupportsGranularity(viewDefinition, request.getGroupByList())) { + // return QueryCost.UNSUPPORTED; + // } double cost; diff --git a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotClientFactory.java b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotClientFactory.java index f276ce84..5be8989c 100644 --- a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotClientFactory.java +++ b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotClientFactory.java @@ -22,8 +22,7 @@ public class PinotClientFactory { private final ConcurrentHashMap clientMap = new ConcurrentHashMap<>(); - private PinotClientFactory() { - } + private PinotClientFactory() {} // Create a Pinot Client. public static PinotClient createPinotClient(String pinotCluster, String pathType, String path) { @@ -104,7 +103,8 @@ private PreparedStatement buildPreparedStatement(String statement, Params params params.getLongParams().forEach(preparedStatement::setLong); params.getDoubleParams().forEach(preparedStatement::setDouble); params.getFloatParams().forEach(preparedStatement::setFloat); - params.getByteStringParams() + params + .getByteStringParams() .forEach((i, b) -> preparedStatement.setString(i, Hex.encodeHexString(b.toByteArray()))); return preparedStatement; } diff --git a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotModule.java b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotModule.java index 56e15c65..e9da9aa3 100644 --- a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotModule.java +++ b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotModule.java @@ -2,8 +2,8 @@ import com.google.inject.AbstractModule; import com.google.inject.multibindings.Multibinder; -import org.hypertrace.core.query.service.RequestHandlerClientConfigRegistry; import org.hypertrace.core.query.service.RequestHandlerBuilder; +import org.hypertrace.core.query.service.RequestHandlerClientConfigRegistry; public class PinotModule extends AbstractModule { diff --git a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotRequestHandlerBuilder.java b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotRequestHandlerBuilder.java index 395453f0..c9e2a3ae 100644 --- a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotRequestHandlerBuilder.java +++ b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/PinotRequestHandlerBuilder.java @@ -3,9 +3,9 @@ import javax.inject.Inject; import org.hypertrace.core.query.service.QueryServiceConfig.RequestHandlerClientConfig; import org.hypertrace.core.query.service.QueryServiceConfig.RequestHandlerConfig; -import org.hypertrace.core.query.service.RequestHandlerClientConfigRegistry; import org.hypertrace.core.query.service.RequestHandler; import org.hypertrace.core.query.service.RequestHandlerBuilder; +import org.hypertrace.core.query.service.RequestHandlerClientConfigRegistry; public class PinotRequestHandlerBuilder implements RequestHandlerBuilder { diff --git a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/QueryRequestToPinotSQLConverter.java b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/QueryRequestToPinotSQLConverter.java index de81783b..3f3d1724 100644 --- a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/QueryRequestToPinotSQLConverter.java +++ b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/QueryRequestToPinotSQLConverter.java @@ -24,9 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * Converts {@link QueryRequest} to Pinot SQL query - */ +/** Converts {@link QueryRequest} to Pinot SQL query */ class QueryRequestToPinotSQLConverter { private static final Logger LOG = LoggerFactory.getLogger(QueryRequestToPinotSQLConverter.class); @@ -201,9 +199,12 @@ private Expression handleValueConversionForLiteralExpression(Expression lhs, Exp String lhsColumnName = lhs.getColumnIdentifier().getColumnName(); try { - Value value = DestinationColumnValueConverter.INSTANCE.convert(rhs.getLiteral().getValue(), - viewDefinition.getColumnType(lhsColumnName)); - return Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue(value)).build(); + Value value = + DestinationColumnValueConverter.INSTANCE.convert( + rhs.getLiteral().getValue(), viewDefinition.getColumnType(lhsColumnName)); + return Expression.newBuilder() + .setLiteral(LiteralConstant.newBuilder().setValue(value)) + .build(); } catch (Exception e) { throw new IllegalArgumentException( String.format( @@ -326,9 +327,7 @@ private LiteralConstant[] convertExpressionToMapLiterals(Expression expression) return literals; } - /** - * TODO:Handle all types - */ + /** TODO:Handle all types */ private String convertLiteralToString(LiteralConstant literal, Params.Builder paramsBuilder) { Value value = literal.getValue(); String ret = null; diff --git a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/ViewColumnFilter.java b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/ViewColumnFilter.java index 1c806fc8..fc9276fe 100644 --- a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/ViewColumnFilter.java +++ b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/ViewColumnFilter.java @@ -1,7 +1,6 @@ package org.hypertrace.core.query.service.pinot; import com.typesafe.config.Config; -import java.util.HashSet; import java.util.Set; /** @@ -10,27 +9,18 @@ * The main view and filtered view can be optimized different for queries and only the queries * matching the view filters will be routed to the filtered view. * - *

Currently, we only support EQ and IN operators in these filters.

- * Example EQ filter: - * { - * column: "EVENT.isEntrySpan" - * operator: "EQ" - * value: "true" - * } + *

Currently, we only support EQ and IN operators in these filters. Example EQ filter: { column: + * "EVENT.isEntrySpan" operator: "EQ" value: "true" } * - * Example IN filter: - * { - * column: "EVENT.statusCode" - * operator: "IN" - * values: ["500", "401"] - * } + *

Example IN filter: { column: "EVENT.statusCode" operator: "IN" values: ["500", "401"] } */ class ViewColumnFilter { private final Operator operator; private final Set values; enum Operator { - IN, EQ + IN, + EQ } public ViewColumnFilter(Operator operator, Set values) { diff --git a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/converters/DestinationColumnValueConverter.java b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/converters/DestinationColumnValueConverter.java index aff1c626..84a3fd69 100644 --- a/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/converters/DestinationColumnValueConverter.java +++ b/query-service-impl/src/main/java/org/hypertrace/core/query/service/pinot/converters/DestinationColumnValueConverter.java @@ -15,11 +15,11 @@ public class DestinationColumnValueConverter { private static final Logger LOG = LoggerFactory.getLogger(DestinationColumnValueConverter.class); - public static final DestinationColumnValueConverter INSTANCE = new DestinationColumnValueConverter(); + public static final DestinationColumnValueConverter INSTANCE = + new DestinationColumnValueConverter(); private static final String EMPTY = ""; - private DestinationColumnValueConverter() { - } + private DestinationColumnValueConverter() {} public Value convert(Value value, ValueType valueType) throws Exception { // Currently, only Pinot's BYTES columns needs transformation since they're actually @@ -47,16 +47,23 @@ public Value convert(Value value, ValueType valueType) throws Exception { return valueBuilder.build(); default: - String msg = String.format("Unsupported value of type: %s while transforming to BYTES.", - value.getValueType().name()); + String msg = + String.format( + "Unsupported value of type: %s while transforming to BYTES.", + value.getValueType().name()); LOG.warn(msg); throw new IllegalArgumentException(msg); } } private ByteString convertToByteString(String inValue) throws DecoderException { - String outValue = (Strings.isNullOrEmpty(inValue) || inValue.trim().equals("null") || - inValue.trim().equals("''") || inValue.trim().equals("{}")) ? EMPTY : inValue; + String outValue = + (Strings.isNullOrEmpty(inValue) + || inValue.trim().equals("null") + || inValue.trim().equals("''") + || inValue.trim().equals("{}")) + ? EMPTY + : inValue; byte[] bytes = Hex.decodeHex(outValue); return ByteString.copyFrom(bytes); } diff --git a/query-service-impl/src/test/java/org/hypertrace/core/query/service/QueryServiceConfigTest.java b/query-service-impl/src/test/java/org/hypertrace/core/query/service/QueryServiceConfigTest.java index 6fb7c06e..721abaa2 100644 --- a/query-service-impl/src/test/java/org/hypertrace/core/query/service/QueryServiceConfigTest.java +++ b/query-service-impl/src/test/java/org/hypertrace/core/query/service/QueryServiceConfigTest.java @@ -23,9 +23,7 @@ public void setup() { appConfig = ConfigFactory.parseURL( requireNonNull( - QueryServiceConfigTest.class - .getClassLoader() - .getResource("application.conf"))); + QueryServiceConfigTest.class.getClassLoader().getResource("application.conf"))); queryServiceConfig = new QueryServiceConfig(appConfig.getConfig("service.config")); } diff --git a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/DestinationColumnValueConverterTest.java b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/DestinationColumnValueConverterTest.java index d78dedd4..be03faa7 100644 --- a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/DestinationColumnValueConverterTest.java +++ b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/DestinationColumnValueConverterTest.java @@ -41,8 +41,10 @@ public void testValidNullFieldsForBytesColumn() throws Exception { @Test public void testInValidNullFieldsForBytesColumn() { DestinationColumnValueConverter converter = DestinationColumnValueConverter.INSTANCE; - Assertions.assertThrows(DecoderException.class, () -> { - converter.convert(getStringValue("abc"), ValueType.BYTES); - }); + Assertions.assertThrows( + DecoderException.class, + () -> { + converter.convert(getStringValue("abc"), ValueType.BYTES); + }); } } diff --git a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/ParamsTest.java b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/ParamsTest.java index 22cf3669..06af562e 100644 --- a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/ParamsTest.java +++ b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/ParamsTest.java @@ -4,24 +4,32 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -/** - * Unit tests for {@link Params} - */ +/** Unit tests for {@link Params} */ public class ParamsTest { @Test public void testEquals() { - Params params = Params.newBuilder().addStringParam("test").addIntegerParam(1) - .addLongParam(100L).addDoubleParam(1.1d).addFloatParam(0.1f).addByteStringParam(ByteString.copyFrom("bytes".getBytes())).build(); + Params params = + Params.newBuilder() + .addStringParam("test") + .addIntegerParam(1) + .addLongParam(100L) + .addDoubleParam(1.1d) + .addFloatParam(0.1f) + .addByteStringParam(ByteString.copyFrom("bytes".getBytes())) + .build(); Assertions.assertEquals(params, params); Assertions.assertEquals(params.hashCode(), params.hashCode()); Assertions.assertNotEquals(params, new Object()); params = Params.newBuilder().addStringParam("test").build(); Assertions.assertEquals(params, Params.newBuilder().addStringParam("test").build()); - Assertions.assertNotEquals(params, Params.newBuilder().addStringParam("test").addIntegerParam(1).build()); + Assertions.assertNotEquals( + params, Params.newBuilder().addStringParam("test").addIntegerParam(1).build()); params = Params.newBuilder().addStringParam("test1").addFloatParam(0.1f).build(); - Assertions.assertEquals(params, Params.newBuilder().addStringParam("test1").addFloatParam(0.1f).build()); - Assertions.assertNotEquals(params, Params.newBuilder().addFloatParam(0.1f).addDoubleParam(0.3d).build()); + Assertions.assertEquals( + params, Params.newBuilder().addStringParam("test1").addFloatParam(0.1f).build()); + Assertions.assertNotEquals( + params, Params.newBuilder().addFloatParam(0.1f).addDoubleParam(0.3d).build()); } } diff --git a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotBasedRequestHandlerTest.java b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotBasedRequestHandlerTest.java index d00603e0..7ba26f21 100644 --- a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotBasedRequestHandlerTest.java +++ b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotBasedRequestHandlerTest.java @@ -50,8 +50,8 @@ public class PinotBasedRequestHandlerTest { public void setUp() { // Mocks PinotClientFactory pinotClientFactoryMock = mock(PinotClientFactory.class); - ResultSetTypePredicateProvider resultSetTypePredicateProviderMock = mock( - ResultSetTypePredicateProvider.class); + ResultSetTypePredicateProvider resultSetTypePredicateProviderMock = + mock(ResultSetTypePredicateProvider.class); Config handlerConfig = firstOf(serviceConfig.getConfigList("queryRequestHandlersConfig")); pinotBasedRequestHandler = @@ -78,30 +78,37 @@ public void testInit() { @Test public void testInitFailure() { - Assertions.assertThrows(RuntimeException.class, () -> { - Config config = ConfigFactory.parseMap(Map.of("name", "test", - "requestHandlerInfo", Map.of())); - new PinotBasedRequestHandler( - config.getString("name"), config.getConfig("requestHandlerInfo")); - }); + Assertions.assertThrows( + RuntimeException.class, + () -> { + Config config = + ConfigFactory.parseMap(Map.of("name", "test", "requestHandlerInfo", Map.of())); + new PinotBasedRequestHandler( + config.getString("name"), config.getConfig("requestHandlerInfo")); + }); } @Test public void testCanHandle() { - for (Config config: serviceConfig.getConfigList("queryRequestHandlersConfig")) { + for (Config config : serviceConfig.getConfigList("queryRequestHandlersConfig")) { PinotBasedRequestHandler handler = new PinotBasedRequestHandler( config.getString("name"), config.getConfig("requestHandlerInfo")); // Verify that the traces handler can traces query. if (config.getString("name").equals("trace-view-handler")) { - QueryRequest request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.duration_millis")) - .setFilter(QueryRequestBuilderUtils.createFilter("Trace.end_time_millis", Operator.GT, - QueryRequestBuilderUtils.createLongLiteralValueExpression(10))) - .build(); + QueryRequest request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.id")) + .addSelection( + QueryRequestBuilderUtils.createColumnExpression("Trace.duration_millis")) + .setFilter( + QueryRequestBuilderUtils.createFilter( + "Trace.end_time_millis", + Operator.GT, + QueryRequestBuilderUtils.createLongLiteralValueExpression(10))) + .build(); ExecutionContext context = new ExecutionContext("__default", request); QueryCost cost = handler.canHandle(request, context); Assertions.assertTrue(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); @@ -111,16 +118,21 @@ public void testCanHandle() { @Test public void testCanHandleNegativeCase() { - for (Config config: serviceConfig.getConfigList("queryRequestHandlersConfig")) { - PinotBasedRequestHandler handler = new PinotBasedRequestHandler(config.getString("name"), config.getConfig("requestHandlerInfo")); + for (Config config : serviceConfig.getConfigList("queryRequestHandlersConfig")) { + PinotBasedRequestHandler handler = + new PinotBasedRequestHandler( + config.getString("name"), config.getConfig("requestHandlerInfo")); // Verify that the traces handler can traces query. if (config.getString("name").equals("trace-view-handler")) { - QueryRequest request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.does_not_exist")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.end_time_millis")) - .addGroupBy(QueryRequestBuilderUtils.createColumnExpression("Trace.tags")) - .build(); + QueryRequest request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection( + QueryRequestBuilderUtils.createColumnExpression("Trace.does_not_exist")) + .addSelection( + QueryRequestBuilderUtils.createColumnExpression("Trace.end_time_millis")) + .addGroupBy(QueryRequestBuilderUtils.createColumnExpression("Trace.tags")) + .build(); ExecutionContext context = new ExecutionContext("__default", request); QueryCost cost = handler.canHandle(request, context); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); @@ -138,66 +150,85 @@ public void testCanHandleWithInViewFilter() { // Verify that the span event view handler can handle the query which has the filter // on the column which has a view filter. if (config.getString("name").equals("span-event-view-handler")) { - QueryRequest request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter(QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "true")) - .addChildFilter(QueryRequestBuilderUtils.createFilter("EVENT.startTime", Operator.GT, - QueryRequestBuilderUtils.createLongLiteralValueExpression(System.currentTimeMillis()))).build()) - .build(); + QueryRequest request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter( + "EVENT.isEntrySpan", "true")) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.startTime", + Operator.GT, + QueryRequestBuilderUtils.createLongLiteralValueExpression( + System.currentTimeMillis()))) + .build()) + .build(); ExecutionContext context = new ExecutionContext("__default", request); QueryCost cost = handler.canHandle(request, context); Assertions.assertTrue(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Entry span "false" filter. - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "false")) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "false")) + .build(); context = new ExecutionContext("__default", request); cost = handler.canHandle(request, context); Assertions.assertTrue(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case. Wrong value in the filter. - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "dummy")) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "dummy")) + .build(); context = new ExecutionContext("__default", request); cost = handler.canHandle(request, context); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case. Unsupported operator in the query filter. - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.LIKE, - QueryRequestBuilderUtils.createStringLiteralValueExpression("dummy"))) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.LIKE, + QueryRequestBuilderUtils.createStringLiteralValueExpression("dummy"))) + .build(); context = new ExecutionContext("__default", request); cost = handler.canHandle(request, context); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case. Any query without filter should not be handled. - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .build(); context = new ExecutionContext("__default", request); QueryCost negativeCost = handler.canHandle(request, context); @@ -216,128 +247,192 @@ public void testCanHandleWithEqViewFilter() { // Verify that the entry span view handler can handle the query which has the filter // on the column which has a view filter. if (config.getString("name").equals("entry-span-view-handler")) { - QueryRequest request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter( - QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "true")) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.startTime", Operator.GT, - QueryRequestBuilderUtils - .createLongLiteralValueExpression(System.currentTimeMillis()))).build()) - .build(); + QueryRequest request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter( + "EVENT.isEntrySpan", "true")) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.startTime", + Operator.GT, + QueryRequestBuilderUtils.createLongLiteralValueExpression( + System.currentTimeMillis()))) + .build()) + .build(); ExecutionContext context = new ExecutionContext("__default", request); QueryCost cost = handler.canHandle(request, context); Assertions.assertTrue(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Positive case with boolean filter. - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(true).setValueType(ValueType.BOOL))) - .build())) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.startTime", Operator.GT, - QueryRequestBuilderUtils - .createLongLiteralValueExpression(System.currentTimeMillis()))).build()) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(true) + .setValueType(ValueType.BOOL))) + .build())) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.startTime", + Operator.GT, + QueryRequestBuilderUtils.createLongLiteralValueExpression( + System.currentTimeMillis()))) + .build()) + .build(); context = new ExecutionContext("__default", request); cost = handler.canHandle(request, context); Assertions.assertTrue(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case with boolean filter but 'OR' operation. - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.OR) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(true).setValueType(ValueType.BOOL))) - .build())) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.startTime", Operator.GT, - QueryRequestBuilderUtils - .createLongLiteralValueExpression(System.currentTimeMillis()))).build()) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.OR) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(true) + .setValueType(ValueType.BOOL))) + .build())) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.startTime", + Operator.GT, + QueryRequestBuilderUtils.createLongLiteralValueExpression( + System.currentTimeMillis()))) + .build()) + .build(); context = new ExecutionContext("__default", request); cost = handler.canHandle(request, context); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case with a complex filter but 'OR' at the root level, hence shouldn't match. - Filter filter = Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter(QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(true).setValueType(ValueType.BOOL))).build())) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.duration_millis", Operator.GT, - QueryRequestBuilderUtils.createLongLiteralValueExpression(10L))).build(); - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.OR) + Filter filter = + Filter.newBuilder() + .setOperator(Operator.AND) .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(false).setValueType(ValueType.BOOL))) + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(true) + .setValueType(ValueType.BOOL))) .build())) - .addChildFilter(filter)) - .build(); + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.duration_millis", + Operator.GT, + QueryRequestBuilderUtils.createLongLiteralValueExpression(10L))) + .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.OR) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(false) + .setValueType(ValueType.BOOL))) + .build())) + .addChildFilter(filter)) + .build(); context = new ExecutionContext("__default", request); cost = handler.canHandle(request, context); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case. Value in query filter is different from the value in view filter - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "false")) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "false")) + .build(); context = new ExecutionContext("__default", request); cost = handler.canHandle(request, context); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case. Unsupported operator in the query filter. - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.IN, - QueryRequestBuilderUtils.createStringLiteralValueExpression("dummy"))) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.IN, + QueryRequestBuilderUtils.createStringLiteralValueExpression("dummy"))) + .build(); context = new ExecutionContext("__default", request); cost = handler.canHandle(request, context); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case. Any query without filter should not be handled. - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .build(); context = new ExecutionContext("__default", request); QueryCost negativeCost = handler.canHandle(request, context); Assertions.assertFalse(negativeCost.getCost() >= 0.0d && negativeCost.getCost() < 1.0d); @@ -356,39 +451,52 @@ public void testCanHandleWithMultipleViewFilters() { // on the column which has a view filter. if (config.getString("name").equals("error-entry-span-view-handler")) { // Positive case, straight forward. - QueryRequest request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter( - QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "true")) - .addChildFilter( - QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "401"))) - .build(); + QueryRequest request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter( + "EVENT.isEntrySpan", "true")) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "401"))) + .build(); ExecutionContext executionContext = new ExecutionContext("__default", request); QueryCost cost = handler.canHandle(request, executionContext); Assertions.assertTrue(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Positive case but the filters are AND'ed in two different child filters. - Filter filter = Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter( - QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "true")) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.startTime", Operator.GT, - QueryRequestBuilderUtils - .createLongLiteralValueExpression(System.currentTimeMillis()))).build(); - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter(filter) - .addChildFilter(QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", 401))) - .build(); + Filter filter = + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "true")) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.startTime", + Operator.GT, + QueryRequestBuilderUtils.createLongLiteralValueExpression( + System.currentTimeMillis()))) + .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter(filter) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", 401))) + .build(); executionContext = new ExecutionContext("__default", request); @@ -397,125 +505,189 @@ public void testCanHandleWithMultipleViewFilters() { // Negative case. Query has only one leaf filter and it matches only one of the view // filters - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(true).setValueType(ValueType.BOOL))) - .build())) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(true) + .setValueType(ValueType.BOOL))) + .build())) + .build(); executionContext = new ExecutionContext("__default", request); cost = handler.canHandle(request, executionContext); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case. Only one view filter is present in the query filters - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(true).setValueType(ValueType.BOOL))) - .build())) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.startTime", Operator.GT, - QueryRequestBuilderUtils - .createLongLiteralValueExpression(System.currentTimeMillis()))).build()) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(true) + .setValueType(ValueType.BOOL))) + .build())) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.startTime", + Operator.GT, + QueryRequestBuilderUtils.createLongLiteralValueExpression( + System.currentTimeMillis()))) + .build()) + .build(); executionContext = new ExecutionContext("__default", request); cost = handler.canHandle(request, executionContext); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case with correct filters but 'OR' operation. - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.OR) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(true).setValueType(ValueType.BOOL))) - .build())) - .addChildFilter(QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", 401L))) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.OR) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(true) + .setValueType(ValueType.BOOL))) + .build())) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", 401L))) + .build(); executionContext = new ExecutionContext("__default", request); cost = handler.canHandle(request, executionContext); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case with a complex filter but 'OR' at the root level, hence shouldn't match. - filter = Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter(QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(true).setValueType(ValueType.BOOL))).build())) - .addChildFilter(QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "401")) - .build(); - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.OR) + filter = + Filter.newBuilder() + .setOperator(Operator.AND) .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(false).setValueType(ValueType.BOOL))) + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(true) + .setValueType(ValueType.BOOL))) .build())) - .addChildFilter(filter)) - .build(); + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "401")) + .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.OR) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(false) + .setValueType(ValueType.BOOL))) + .build())) + .addChildFilter(filter)) + .build(); executionContext = new ExecutionContext("__default", request); cost = handler.canHandle(request, executionContext); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case. Value in query filter is different from the value in view filter - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter( - QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "true")) - .addChildFilter( - QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "200"))) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter( + "EVENT.isEntrySpan", "true")) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "200"))) + .build(); executionContext = new ExecutionContext("__default", request); cost = handler.canHandle(request, executionContext); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case. Unsupported operator in the query filter. - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.IN, - QueryRequestBuilderUtils.createStringLiteralValueExpression("dummy"))) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.IN, + QueryRequestBuilderUtils.createStringLiteralValueExpression("dummy"))) + .build(); executionContext = new ExecutionContext("__default", request); cost = handler.canHandle(request, executionContext); Assertions.assertFalse(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case. Any query without filter should not be handled. - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .build(); executionContext = new ExecutionContext("__default", request); QueryCost negativeCost = handler.canHandle(request, executionContext); Assertions.assertFalse(negativeCost.getCost() >= 0.0d && negativeCost.getCost() < 1.0d); @@ -534,46 +706,63 @@ public void testCanHandleWithMultipleViewFiltersAndRepeatedQueryFilters() { // on the column which has a view filter. if (config.getString("name").equals("error-entry-span-view-handler")) { // Positive case, straight forward. - Filter filter = Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter( - QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "true")) - .addChildFilter( - QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "401")) - .build(); - QueryRequest request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter(filter) - .addChildFilter(Filter.newBuilder(filter))) - .build(); + Filter filter = + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "true")) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "401")) + .build(); + QueryRequest request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter(filter) + .addChildFilter(Filter.newBuilder(filter))) + .build(); ExecutionContext context = new ExecutionContext("__default", request); QueryCost cost = handler.canHandle(request, context); Assertions.assertTrue(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Positive case - Filter childFilter = Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter( - QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "true")) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.startTime", Operator.GT, - QueryRequestBuilderUtils - .createLongLiteralValueExpression(System.currentTimeMillis()))).build(); - filter = Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter(childFilter) - .addChildFilter(QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", 401)) - .build(); - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter(filter).addChildFilter(Filter.newBuilder(filter))) - .build(); + Filter childFilter = + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "true")) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.startTime", + Operator.GT, + QueryRequestBuilderUtils.createLongLiteralValueExpression( + System.currentTimeMillis()))) + .build(); + filter = + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter(childFilter) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", 401)) + .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter(filter) + .addChildFilter(Filter.newBuilder(filter))) + .build(); context = new ExecutionContext("__default", request); @@ -581,34 +770,62 @@ public void testCanHandleWithMultipleViewFiltersAndRepeatedQueryFilters() { Assertions.assertTrue(cost.getCost() >= 0.0d && cost.getCost() < 1.0d); // Negative case. Only one view filter is present in the query filters. - Filter filter1 = Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(true).setValueType(ValueType.BOOL))) - .build())) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.startTime", Operator.GT, - QueryRequestBuilderUtils - .createLongLiteralValueExpression(System.currentTimeMillis()))).build(); - Filter filter2 = Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(true).setValueType(ValueType.BOOL))) - .build())) - .addChildFilter( - QueryRequestBuilderUtils.createFilter("EVENT.startTime", Operator.LT, - QueryRequestBuilderUtils - .createLongLiteralValueExpression(System.currentTimeMillis() - 10000))).build(); - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter(filter1).addChildFilter(filter2)) - .build(); + Filter filter1 = + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(true) + .setValueType(ValueType.BOOL))) + .build())) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.startTime", + Operator.GT, + QueryRequestBuilderUtils.createLongLiteralValueExpression( + System.currentTimeMillis()))) + .build(); + Filter filter2 = + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(true) + .setValueType(ValueType.BOOL))) + .build())) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.startTime", + Operator.LT, + QueryRequestBuilderUtils.createLongLiteralValueExpression( + System.currentTimeMillis() - 10000))) + .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter(filter1) + .addChildFilter(filter2)) + .build(); context = new ExecutionContext("__default", request); cost = handler.canHandle(request, context); @@ -616,26 +833,54 @@ public void testCanHandleWithMultipleViewFiltersAndRepeatedQueryFilters() { // Positive case with a complex filter and 'OR' at the root level, but both sides of 'OR' // match the view filter. - filter1 = Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter(QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(true).setValueType(ValueType.BOOL))).build())) - .addChildFilter(QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "401")) - .build(); - filter2 = Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter(QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(true).setValueType(ValueType.BOOL))).build())) - .addChildFilter(QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "500")) - .build(); - request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.OR) - .addChildFilter(filter1).addChildFilter(filter2)) - .build(); + filter1 = + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(true) + .setValueType(ValueType.BOOL))) + .build())) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "401")) + .build(); + filter2 = + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(true) + .setValueType(ValueType.BOOL))) + .build())) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "500")) + .build(); + request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.OR) + .addChildFilter(filter1) + .addChildFilter(filter2)) + .build(); context = new ExecutionContext("__default", request); cost = handler.canHandle(request, context); @@ -646,19 +891,25 @@ public void testCanHandleWithMultipleViewFiltersAndRepeatedQueryFilters() { @Test void testCanHandle_costShouldBeLessThanHalf() { - for (Config config: serviceConfig.getConfigList("queryRequestHandlersConfig")) { + for (Config config : serviceConfig.getConfigList("queryRequestHandlersConfig")) { PinotBasedRequestHandler handler = new PinotBasedRequestHandler( config.getString("name"), config.getConfig("requestHandlerInfo")); // this timestamp should be less than the view retention time long oneHourAgoTimestamp = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1); - QueryRequest request = QueryRequest.newBuilder() - .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.duration_millis")) - .setFilter(QueryRequestBuilderUtils.createFilter("Trace.start_time_millis", Operator.GE, - QueryRequestBuilderUtils.createLongLiteralValueExpression(oneHourAgoTimestamp))) - .build(); + QueryRequest request = + QueryRequest.newBuilder() + .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.id")) + .addSelection( + QueryRequestBuilderUtils.createColumnExpression("Trace.duration_millis")) + .setFilter( + QueryRequestBuilderUtils.createFilter( + "Trace.start_time_millis", + Operator.GE, + QueryRequestBuilderUtils.createLongLiteralValueExpression( + oneHourAgoTimestamp))) + .build(); ExecutionContext context = new ExecutionContext("__default", request); QueryCost cost = handler.canHandle(request, context); @@ -672,19 +923,24 @@ void testCanHandle_costShouldBeLessThanHalf() { @Test void testCanHandle_costShouldBeMoreThanHalf() { - for (Config config: serviceConfig.getConfigList("queryRequestHandlersConfig")) { + for (Config config : serviceConfig.getConfigList("queryRequestHandlersConfig")) { PinotBasedRequestHandler handler = new PinotBasedRequestHandler( config.getString("name"), config.getConfig("requestHandlerInfo")); // this timestamp should be greater than the view retention time long threeDaysAgoTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(3); - QueryRequest request = QueryRequest.newBuilder() - .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.duration_millis")) - .setFilter(QueryRequestBuilderUtils.createFilter("Trace.start_time_millis", Operator.GE, - QueryRequestBuilderUtils.createLongLiteralValueExpression(threeDaysAgoTime))) - .build(); + QueryRequest request = + QueryRequest.newBuilder() + .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.id")) + .addSelection( + QueryRequestBuilderUtils.createColumnExpression("Trace.duration_millis")) + .setFilter( + QueryRequestBuilderUtils.createFilter( + "Trace.start_time_millis", + Operator.GE, + QueryRequestBuilderUtils.createLongLiteralValueExpression(threeDaysAgoTime))) + .build(); ExecutionContext context = new ExecutionContext("__default", request); QueryCost cost = handler.canHandle(request, context); @@ -705,7 +961,8 @@ public void testConvertSimpleSelectionsQueryResultSet() throws IOException { {"operation-name-2", "service-name-2", "72", "78"}, {"operation-name-3", "service-name-3", "73", "77"} }; - List columnNames = List.of("operation_name", "service_name", "start_time_millis", "duration"); + List columnNames = + List.of("operation_name", "service_name", "start_time_millis", "duration"); ResultSet resultSet = mockResultSet(4, 4, columnNames, resultTable); ResultSetGroup resultSetGroup = mockResultSetGroup(List.of(resultSet)); @@ -722,7 +979,8 @@ public void testConvertAggregationColumnsQueryResultSet() throws IOException { {"operation-name-12", "112", "42", "23"}, {"operation-name-13", "113", "43", "24"} }; - List columnNames = List.of("operation_name", "avg(duration)", "count(*)", "max(duration)"); + List columnNames = + List.of("operation_name", "avg(duration)", "count(*)", "max(duration)"); ResultSet resultSet = mockResultSet(4, 4, columnNames, resultTable); ResultSetGroup resultSetGroup = mockResultSetGroup(List.of(resultSet)); @@ -793,7 +1051,8 @@ public void testConvertSelectionsWithMapKeysAndValuesQueryResultSet() throws IOE @Test public void testConvertMultipleResultSetsInFResultSetGroup() throws IOException { - List columnNames = List.of("operation_name", "avg(duration)", "count(*)", "max(duration)"); + List columnNames = + List.of("operation_name", "avg(duration)", "count(*)", "max(duration)"); String[][] resultTable1 = new String[][] { {"operation-name-10", "110", "40", "21"}, @@ -849,27 +1108,30 @@ public void testNullTenantIdQueryRequestContextThrowsNPE() { public void testGroupBysAndAggregationsMixedWithSelectionsThrowsExceptionWhenDistinctSelectionIsSpecified() { // Setting distinct selections and mixing selections and group bys should throw exception - QueryRequest request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("col1")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("col2")) - .addGroupBy(QueryRequestBuilderUtils.createColumnExpression("col3")) - .build(); + QueryRequest request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("col1")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("col2")) + .addGroupBy(QueryRequestBuilderUtils.createColumnExpression("col3")) + .build(); Assertions.assertThrows( IllegalArgumentException.class, - () -> pinotBasedRequestHandler.handleRequest( - request, - new ExecutionContext("test-tenant-id", request)).blockingSubscribe()); + () -> + pinotBasedRequestHandler + .handleRequest(request, new ExecutionContext("test-tenant-id", request)) + .blockingSubscribe()); // Setting distinct selections and mixing selections and aggregations should throw exception - QueryRequest request2 = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("col1")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("col2")) - .addAggregation( - QueryRequestBuilderUtils.createFunctionExpression( - "AVG", "duration", "avg_duration")) - .build(); + QueryRequest request2 = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("col1")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("col2")) + .addAggregation( + QueryRequestBuilderUtils.createFunctionExpression( + "AVG", "duration", "avg_duration")) + .build(); Assertions.assertThrows( IllegalArgumentException.class, () -> @@ -879,15 +1141,16 @@ public void testNullTenantIdQueryRequestContextThrowsNPE() { // Setting distinct selections and mixing selections, group bys and aggregations should throw // exception - QueryRequest request3 = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("col1")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("col2")) - .addGroupBy(QueryRequestBuilderUtils.createColumnExpression("col3")) - .addAggregation( - QueryRequestBuilderUtils.createFunctionExpression( - "AVG", "duration", "avg_duration")) - .build(); + QueryRequest request3 = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("col1")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("col2")) + .addGroupBy(QueryRequestBuilderUtils.createColumnExpression("col3")) + .addAggregation( + QueryRequestBuilderUtils.createFunctionExpression( + "AVG", "duration", "avg_duration")) + .build(); Assertions.assertThrows( IllegalArgumentException.class, () -> @@ -910,10 +1173,10 @@ public void testWithMockPinotClient() throws IOException { String[][] resultTable = new String[][] { - {"trace-id-1", "80"}, - {"trace-id-2", "79"}, - {"trace-id-3", "78"}, - {"trace-id-4", "77"} + {"trace-id-1", "80"}, + {"trace-id-2", "79"}, + {"trace-id-3", "78"}, + {"trace-id-4", "77"} }; List columnNames = List.of("trace_id", "duration_millis"); ResultSet resultSet = mockResultSet(4, 2, columnNames, resultTable); @@ -937,10 +1200,12 @@ public boolean isResultTableResultSetType(ResultSet resultSet) { }, factory); - QueryRequest request = QueryRequest.newBuilder() - .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.duration_millis")) - .build(); + QueryRequest request = + QueryRequest.newBuilder() + .addSelection(QueryRequestBuilderUtils.createColumnExpression("Trace.id")) + .addSelection( + QueryRequestBuilderUtils.createColumnExpression("Trace.duration_millis")) + .build(); ExecutionContext context = new ExecutionContext("__default", request); verifyResponseRows(handler.handleRequest(request, context), resultTable); } @@ -960,10 +1225,10 @@ public void testViewColumnFilterRemoval() throws IOException { String[][] resultTable = new String[][] { - {"test-span-id-1", "trace-id-1"}, - {"test-span-id-2", "trace-id-1"}, - {"test-span-id-3", "trace-id-1"}, - {"test-span-id-4", "trace-id-2"} + {"test-span-id-1", "trace-id-1"}, + {"test-span-id-2", "trace-id-1"}, + {"test-span-id-3", "trace-id-1"}, + {"test-span-id-4", "trace-id-2"} }; List columnNames = List.of("span_id", "trace_id"); ResultSet resultSet = mockResultSet(4, 2, columnNames, resultTable); @@ -986,15 +1251,24 @@ public boolean isResultTableResultSetType(ResultSet resultSet) { }, factory); - QueryRequest request = QueryRequest.newBuilder() - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter(QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "true")) - .addChildFilter(QueryRequestBuilderUtils.createFilter("EVENT.startTime", Operator.GT, - QueryRequestBuilderUtils.createStringLiteralValueExpression("1000"))) - .addChildFilter(QueryRequestBuilderUtils.createInFilter("EVENT.isEntrySpan", List.of("true", "false")))) - .build(); + QueryRequest request = + QueryRequest.newBuilder() + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.isEntrySpan", "true")) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.startTime", + Operator.GT, + QueryRequestBuilderUtils.createStringLiteralValueExpression("1000"))) + .addChildFilter( + QueryRequestBuilderUtils.createInFilter( + "EVENT.isEntrySpan", List.of("true", "false")))) + .build(); ExecutionContext context = new ExecutionContext("__default", request); QueryCost cost = handler.canHandle(request, context); @@ -1003,8 +1277,14 @@ public boolean isResultTableResultSetType(ResultSet resultSet) { // The query filter is based on both isEntrySpan and startTime. Since the viewFilter // checks for both the true and false values of isEntrySpan and query filter only needs // "true", isEntrySpan predicate is still passed to the store in the query. - String expectedQuery = "Select span_id, trace_id FROM spanEventView WHERE tenant_id = ? AND ( is_entry_span = ? AND start_time_millis > ? )"; - Params params = Params.newBuilder().addStringParam("__default").addStringParam("true").addStringParam("1000").build(); + String expectedQuery = + "Select span_id, trace_id FROM spanEventView WHERE tenant_id = ? AND ( is_entry_span = ? AND start_time_millis > ? )"; + Params params = + Params.newBuilder() + .addStringParam("__default") + .addStringParam("true") + .addStringParam("1000") + .build(); when(pinotClient.executeQuery(expectedQuery, params)).thenReturn(resultSetGroup); verifyResponseRows(handler.handleRequest(request, context), resultTable); @@ -1025,10 +1305,10 @@ public void testViewColumnFilterRemovalComplexCase() throws IOException { String[][] resultTable = new String[][] { - {"1598922083000", "span-1", "trace-1"}, - {"1598922083010", "span-2", "trace-1"}, - {"1598922083020", "span-3", "trace-1"}, - {"1598922083230", "span-4", "trace-2"} + {"1598922083000", "span-1", "trace-1"}, + {"1598922083010", "span-2", "trace-1"}, + {"1598922083020", "span-3", "trace-1"}, + {"1598922083230", "span-4", "trace-2"} }; List columnNames = List.of("start_time_millis", "span_id", "trace_id"); ResultSet resultSet = mockResultSet(4, 3, columnNames, resultTable); @@ -1051,27 +1331,44 @@ public boolean isResultTableResultSetType(ResultSet resultSet) { }, factory); - Filter filter1 = Filter.newBuilder().setOperator(Operator.AND) - .addChildFilter(QueryRequestBuilderUtils.createFilter("EVENT.isEntrySpan", Operator.EQ, - Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setBoolean(true).setValueType(ValueType.BOOL))).build())) - .addChildFilter(QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "401")) - .build(); - QueryRequest request = QueryRequest.newBuilder() - .setDistinctSelections(true) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) - .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) - .setFilter(Filter.newBuilder().setOperator(Operator.OR) - .addChildFilter(filter1).addChildFilter(Filter.newBuilder(filter1))) - .build(); + Filter filter1 = + Filter.newBuilder() + .setOperator(Operator.AND) + .addChildFilter( + QueryRequestBuilderUtils.createFilter( + "EVENT.isEntrySpan", + Operator.EQ, + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setBoolean(true) + .setValueType(ValueType.BOOL))) + .build())) + .addChildFilter( + QueryRequestBuilderUtils.createEqualsFilter("EVENT.statusCode", "401")) + .build(); + QueryRequest request = + QueryRequest.newBuilder() + .setDistinctSelections(true) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.startTime")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.id")) + .addSelection(QueryRequestBuilderUtils.createColumnExpression("EVENT.traceId")) + .setFilter( + Filter.newBuilder() + .setOperator(Operator.OR) + .addChildFilter(filter1) + .addChildFilter(Filter.newBuilder(filter1))) + .build(); ExecutionContext context = new ExecutionContext("__default", request); QueryCost cost = handler.canHandle(request, context); Assertions.assertTrue(cost.getCost() > 0.0d && cost.getCost() < 1d); // Though there is isEntrySpan and statusCode used in the filters, they both should be // removed by the view filters and hence the actual query only has tenant_id in the filter. - String expectedQuery = "Select DISTINCT start_time_millis, span_id, trace_id FROM spanEventView WHERE tenant_id = ? AND status_code = ?"; + String expectedQuery = + "Select DISTINCT start_time_millis, span_id, trace_id FROM spanEventView WHERE tenant_id = ? AND status_code = ?"; Params params = Params.newBuilder().addStringParam("__default").addStringParam("401").build(); when(pinotClient.executeQuery(expectedQuery, params)).thenReturn(resultSetGroup); diff --git a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotQueryTest.java b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotQueryTest.java index 7eff55c4..09527ae7 100644 --- a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotQueryTest.java +++ b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotQueryTest.java @@ -27,13 +27,14 @@ public void testPinotQuery() { public void testResolveStatement() { String statement = PinotClientFactory.PinotClient.resolveStatement( - "select * from table where team in (?, ?, ?)", - Params.newBuilder() - .addStringParam("abc") - .addStringParam("pqr with (?)") - .addStringParam("xyz") - .build()); + "select * from table where team in (?, ?, ?)", + Params.newBuilder() + .addStringParam("abc") + .addStringParam("pqr with (?)") + .addStringParam("xyz") + .build()); - Assertions.assertEquals("select * from table where team in ('abc', 'pqr with (?)', 'xyz')", statement); + Assertions.assertEquals( + "select * from table where team in ('abc', 'pqr with (?)', 'xyz')", statement); } } diff --git a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotResultAnalyzerTest.java b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotResultAnalyzerTest.java index 59d6cb50..5a88bcd3 100644 --- a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotResultAnalyzerTest.java +++ b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotResultAnalyzerTest.java @@ -54,12 +54,13 @@ public void setup() { resultSet = mock(ResultSet.class); pinotMapConverter = new PinotMapConverter(); - Map> viewDefinitionMap = ImmutableMap.>builder() - .put(LOGICAL_COL1, Lists.newArrayList(PHYS_COL1)) - .put(LOGICAL_COL2, Lists.newArrayList(PHYS_COL2)) - .put(LOGICAL_MAP_NAME1, Lists.newArrayList(MAP1_KEY_NAME, MAP1_VAL_NAME)) - .put(LOGICAL_MAP_NAME2, Lists.newArrayList(MAP2_KEY_NAME, MAP2_VAL_NAME)) - .build(); + Map> viewDefinitionMap = + ImmutableMap.>builder() + .put(LOGICAL_COL1, Lists.newArrayList(PHYS_COL1)) + .put(LOGICAL_COL2, Lists.newArrayList(PHYS_COL2)) + .put(LOGICAL_MAP_NAME1, Lists.newArrayList(MAP1_KEY_NAME, MAP1_VAL_NAME)) + .put(LOGICAL_MAP_NAME2, Lists.newArrayList(MAP2_KEY_NAME, MAP2_VAL_NAME)) + .build(); viewDefinitionMap.forEach( (k, v) -> { when(viewDefinition.getPhysicalColumnNames(k)).thenReturn(v); @@ -74,19 +75,21 @@ public void setup() { when(viewDefinition.getKeyColumnNameForMap(LOGICAL_MAP_NAME2)).thenReturn(MAP2_KEY_NAME); when(viewDefinition.getValueColumnNameForMap(LOGICAL_MAP_NAME2)).thenReturn(MAP2_VAL_NAME); - LinkedHashSet selectedAttributes = new LinkedHashSet<>( - ImmutableList.builder() - .add(LOGICAL_COL1) - .add(LOGICAL_MAP_NAME1) - .add(LOGICAL_COL2) - .add(LOGICAL_MAP_NAME2) - .build()); + LinkedHashSet selectedAttributes = + new LinkedHashSet<>( + ImmutableList.builder() + .add(LOGICAL_COL1) + .add(LOGICAL_MAP_NAME1) + .add(LOGICAL_COL2) + .add(LOGICAL_MAP_NAME2) + .build()); resultSetColumnNames = Lists.newArrayList( PHYS_COL1, MAP1_KEY_NAME, MAP1_VAL_NAME, PHYS_COL2, MAP2_KEY_NAME, MAP2_VAL_NAME); - List resultSetColumnValues = Lists.newArrayList( - VAL_COL1, MAP1_KEY_VAL, MAP1_VAL_VAL, VAL_COL2, MAP2_KEY_VAL, MAP2_VAL_VAL); + List resultSetColumnValues = + Lists.newArrayList( + VAL_COL1, MAP1_KEY_VAL, MAP1_VAL_VAL, VAL_COL2, MAP2_KEY_VAL, MAP2_VAL_VAL); mockResultSet(resultSetColumnNames, resultSetColumnValues); target = PinotResultAnalyzer.create(resultSet, selectedAttributes, viewDefinition); diff --git a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotUtilsTest.java b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotUtilsTest.java index 37f38842..42e099e4 100644 --- a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotUtilsTest.java +++ b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/PinotUtilsTest.java @@ -19,13 +19,13 @@ public void testZkPath() { @Test public void testGetMetricName() { - Assertions.assertEquals("span.event.view.handler", - PinotUtils.getMetricName("span-event-view-handler")); + Assertions.assertEquals( + "span.event.view.handler", PinotUtils.getMetricName("span-event-view-handler")); - Assertions.assertEquals("span.event.view.handler", - PinotUtils.getMetricName("span.event-view-handler")); + Assertions.assertEquals( + "span.event.view.handler", PinotUtils.getMetricName("span.event-view-handler")); - Assertions.assertEquals("span_event.view.handler", - PinotUtils.getMetricName("span_event-view-handler")); + Assertions.assertEquals( + "span_event.view.handler", PinotUtils.getMetricName("span_event-view-handler")); } } diff --git a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/QueryRequestToPinotSQLConverterTest.java b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/QueryRequestToPinotSQLConverterTest.java index 6fd9d4ac..86f3606c 100644 --- a/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/QueryRequestToPinotSQLConverterTest.java +++ b/query-service-impl/src/test/java/org/hypertrace/core/query/service/pinot/QueryRequestToPinotSQLConverterTest.java @@ -173,8 +173,8 @@ public void testQueryWithStringFilter() { public void testSQLiWithStringValueFilter() { QueryRequest queryRequest = buildSimpleQueryWithFilter( - createStringFilter("Span.displaySpanName", Operator.EQ, - "GET /login' OR tenant_id = 'tenant2")); + createStringFilter( + "Span.displaySpanName", Operator.EQ, "GET /login' OR tenant_id = 'tenant2")); assertPQLQuery( queryRequest, @@ -425,13 +425,18 @@ public void testQueryWithStringArray() { + " = '" + TENANT_ID + "' " - + "AND span_id IN ('" + spanId1 + "', '" + spanId2 + "')"); + + "AND span_id IN ('" + + spanId1 + + "', '" + + spanId2 + + "')"); } @Test public void testSQLiWithStringArrayFilter() { Builder builder = QueryRequest.newBuilder(); - ColumnIdentifier spanId = ColumnIdentifier.newBuilder().setColumnName("Span.displaySpanName").build(); + ColumnIdentifier spanId = + ColumnIdentifier.newBuilder().setColumnName("Span.displaySpanName").build(); builder.addSelection(Expression.newBuilder().setColumnIdentifier(spanId).build()); String span1 = "1') OR tenant_id = 'tenant2' and span_name IN ('1"; @@ -571,15 +576,13 @@ public void testQueryWithBytesColumnWithValidId() { builder.addSelection(Expression.newBuilder().setColumnIdentifier(spanId).build()); // create NEQ filter - Filter parentIdFilter = QueryRequestBuilderUtils - .createColumnValueFilter("Span.attributes.parent_span_id", - Operator.EQ, "042e5523ff6b2506").build(); + Filter parentIdFilter = + QueryRequestBuilderUtils.createColumnValueFilter( + "Span.attributes.parent_span_id", Operator.EQ, "042e5523ff6b2506") + .build(); Filter andFilter = - Filter.newBuilder() - .setOperator(Operator.AND) - .addChildFilter(parentIdFilter) - .build(); + Filter.newBuilder().setOperator(Operator.AND).addChildFilter(parentIdFilter).build(); builder.setFilter(andFilter); builder.setLimit(5); @@ -605,19 +608,19 @@ public void testQueryWithBytesColumnWithInValidId() { builder.addSelection(Expression.newBuilder().setColumnIdentifier(spanId).build()); // create NEQ filter - Filter parentIdFilter = QueryRequestBuilderUtils - .createColumnValueFilter("Span.attributes.parent_span_id", - Operator.EQ, "042e5523ff6b250L").build(); + Filter parentIdFilter = + QueryRequestBuilderUtils.createColumnValueFilter( + "Span.attributes.parent_span_id", Operator.EQ, "042e5523ff6b250L") + .build(); Filter andFilter = - Filter.newBuilder() - .setOperator(Operator.AND) - .addChildFilter(parentIdFilter) - .build(); + Filter.newBuilder().setOperator(Operator.AND).addChildFilter(parentIdFilter).build(); builder.setFilter(andFilter); builder.setLimit(5); - assertExceptionOnPQLQuery(builder.build(), IllegalArgumentException.class, + assertExceptionOnPQLQuery( + builder.build(), + IllegalArgumentException.class, "Invalid input:{ string: \"042e5523ff6b250L\"\n" + " } for bytes column:{ parent_span_id }"); } @@ -631,15 +634,13 @@ public void testQueryWithBytesColumnWithNullId() { builder.addSelection(Expression.newBuilder().setColumnIdentifier(spanId).build()); // create NEQ filter - Filter parentIdFilter = QueryRequestBuilderUtils - .createColumnValueFilter("Span.attributes.parent_span_id", - Operator.NEQ, "null").build(); + Filter parentIdFilter = + QueryRequestBuilderUtils.createColumnValueFilter( + "Span.attributes.parent_span_id", Operator.NEQ, "null") + .build(); Filter andFilter = - Filter.newBuilder() - .setOperator(Operator.AND) - .addChildFilter(parentIdFilter) - .build(); + Filter.newBuilder().setOperator(Operator.AND).addChildFilter(parentIdFilter).build(); builder.setFilter(andFilter); builder.setLimit(5); @@ -665,15 +666,13 @@ public void testQueryWithBytesColumnWithEmptyId() { builder.addSelection(Expression.newBuilder().setColumnIdentifier(spanId).build()); // create NEQ filter - Filter parentIdFilter = QueryRequestBuilderUtils - .createColumnValueFilter("Span.attributes.parent_span_id", - Operator.NEQ, "''").build(); + Filter parentIdFilter = + QueryRequestBuilderUtils.createColumnValueFilter( + "Span.attributes.parent_span_id", Operator.NEQ, "''") + .build(); Filter andFilter = - Filter.newBuilder() - .setOperator(Operator.AND) - .addChildFilter(parentIdFilter) - .build(); + Filter.newBuilder().setOperator(Operator.AND).addChildFilter(parentIdFilter).build(); builder.setFilter(andFilter); builder.setLimit(5); @@ -693,19 +692,22 @@ public void testQueryWithBytesColumnWithEmptyId() { @Test public void testQueryWithBytesColumnInFilter() { Builder builder = QueryRequest.newBuilder(); - ColumnIdentifier durationColumn = ColumnIdentifier.newBuilder() - .setColumnName("Span.metrics.duration_millis").build(); + ColumnIdentifier durationColumn = + ColumnIdentifier.newBuilder().setColumnName("Span.metrics.duration_millis").build(); builder.addSelection(Expression.newBuilder().setColumnIdentifier(durationColumn)); ColumnIdentifier.Builder spanId = ColumnIdentifier.newBuilder().setColumnName("Span.id"); // Though span id is bytes in Pinot, top layers send the value as hex string. - Value.Builder value = Value.newBuilder().setValueType(ValueType.STRING_ARRAY) - .addAllStringArray(List.of("042e5523ff6b2506")); - builder.setFilter(Filter.newBuilder() - .setLhs(Expression.newBuilder().setColumnIdentifier(spanId)) - .setOperator(Operator.IN) - .setRhs(Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue(value))) - ); + Value.Builder value = + Value.newBuilder() + .setValueType(ValueType.STRING_ARRAY) + .addAllStringArray(List.of("042e5523ff6b2506")); + builder.setFilter( + Filter.newBuilder() + .setLhs(Expression.newBuilder().setColumnIdentifier(spanId)) + .setOperator(Operator.IN) + .setRhs( + Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue(value)))); assertPQLQuery( builder.build(), @@ -727,15 +729,11 @@ public void testQueryWithStringColumnWithNullString() { builder.addSelection(Expression.newBuilder().setColumnIdentifier(spanId).build()); // create NEQ filter - Filter parentIdFilter = QueryRequestBuilderUtils - .createColumnValueFilter("Span.id", - Operator.NEQ, "null").build(); + Filter parentIdFilter = + QueryRequestBuilderUtils.createColumnValueFilter("Span.id", Operator.NEQ, "null").build(); Filter andFilter = - Filter.newBuilder() - .setOperator(Operator.AND) - .addChildFilter(parentIdFilter) - .build(); + Filter.newBuilder().setOperator(Operator.AND).addChildFilter(parentIdFilter).build(); builder.setFilter(andFilter); builder.setLimit(5); @@ -761,16 +759,21 @@ public void testQueryWithLongColumn() { builder.addSelection(Expression.newBuilder().setColumnIdentifier(spanId).build()); // create an and filter with Long literal type - ColumnIdentifier durationColumn = ColumnIdentifier.newBuilder() - .setColumnName("Span.metrics.duration_millis").build(); - Filter andFilter = Filter.newBuilder() + ColumnIdentifier durationColumn = + ColumnIdentifier.newBuilder().setColumnName("Span.metrics.duration_millis").build(); + Filter andFilter = + Filter.newBuilder() .setOperator(Operator.GE) .setLhs(Expression.newBuilder().setColumnIdentifier(durationColumn).build()) - .setRhs(Expression.newBuilder() - .setLiteral(LiteralConstant.newBuilder() - .setValue(Value.newBuilder() + .setRhs( + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() .setValueType(ValueType.LONG) - .setLong(1000L).build())) + .setLong(1000L) + .build())) .build()) .build(); @@ -780,14 +783,14 @@ public void testQueryWithLongColumn() { QueryRequest request = builder.build(); assertPQLQuery( - request, - "SELECT span_id FROM SpanEventView " - + "WHERE " - + viewDefinition.getTenantIdColumn() - + " = '" - + TENANT_ID - + "' " - + "AND duration_millis >= 1000 limit 5"); + request, + "SELECT span_id FROM SpanEventView " + + "WHERE " + + viewDefinition.getTenantIdColumn() + + " = '" + + TENANT_ID + + "' " + + "AND duration_millis >= 1000 limit 5"); } @Test @@ -796,29 +799,34 @@ public void testQueryWithLongColumnWithLikeFilter() { ColumnIdentifier spanId = ColumnIdentifier.newBuilder().setColumnName("Span.id").build(); builder.addSelection(Expression.newBuilder().setColumnIdentifier(spanId).build()); - ColumnIdentifier durationColumn = ColumnIdentifier.newBuilder() - .setColumnName("Span.metrics.duration_millis").build(); + ColumnIdentifier durationColumn = + ColumnIdentifier.newBuilder().setColumnName("Span.metrics.duration_millis").build(); Filter likeFilter = - Filter.newBuilder() - .setOperator(Operator.LIKE) - .setLhs(Expression.newBuilder().setColumnIdentifier(durationColumn).build()) - .setRhs(Expression.newBuilder() - .setLiteral(LiteralConstant.newBuilder() - .setValue(Value.newBuilder(). - setValueType(ValueType.LONG).setLong(5000L).build())) - .build()) - .build(); + Filter.newBuilder() + .setOperator(Operator.LIKE) + .setLhs(Expression.newBuilder().setColumnIdentifier(durationColumn).build()) + .setRhs( + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue( + Value.newBuilder() + .setValueType(ValueType.LONG) + .setLong(5000L) + .build())) + .build()) + .build(); builder.setFilter(likeFilter); assertPQLQuery( - builder.build(), - "SELECT span_id FROM SpanEventView " - + "WHERE " - + viewDefinition.getTenantIdColumn() - + " = '" - + TENANT_ID - + "' " - + "AND REGEXP_LIKE(duration_millis,5000)"); + builder.build(), + "SELECT span_id FROM SpanEventView " + + "WHERE " + + viewDefinition.getTenantIdColumn() + + " = '" + + TENANT_ID + + "' " + + "AND REGEXP_LIKE(duration_millis,5000)"); } @Test @@ -826,11 +834,18 @@ public void testQueryWithPercentileAggregation() { Filter startTimeFilter = createTimeFilter("Span.start_time_millis", Operator.GT, 1570658506605L); Filter endTimeFilter = createTimeFilter("Span.end_time_millis", Operator.LT, 1570744906673L); - Expression percentileAgg = Expression.newBuilder().setFunction( - Function.newBuilder().setAlias("P99_duration").setFunctionName("PERCENTILE99") - .addArguments(Expression.newBuilder().setColumnIdentifier( - ColumnIdentifier.newBuilder().setColumnName("Span.metrics.duration_millis"))) - ).build(); + Expression percentileAgg = + Expression.newBuilder() + .setFunction( + Function.newBuilder() + .setAlias("P99_duration") + .setFunctionName("PERCENTILE99") + .addArguments( + Expression.newBuilder() + .setColumnIdentifier( + ColumnIdentifier.newBuilder() + .setColumnName("Span.metrics.duration_millis")))) + .build(); QueryRequest queryRequest = QueryRequest.newBuilder() @@ -860,30 +875,30 @@ public void testQueryWithPercentileAggregation() { public void testQueryWithNulls() { Expression conditionalString = Expression.newBuilder() - .setFunction( - Function.newBuilder() - .setFunctionName(QueryFunctionConstants.QUERY_FUNCTION_CONDITIONAL) - .addArguments(createStringLiteralValueExpression("true")) - .addArguments(createColumnExpression("Span.id")) - .addArguments(createNullStringLiteralExpression())) - .build(); + .setFunction( + Function.newBuilder() + .setFunctionName(QueryFunctionConstants.QUERY_FUNCTION_CONDITIONAL) + .addArguments(createStringLiteralValueExpression("true")) + .addArguments(createColumnExpression("Span.id")) + .addArguments(createNullStringLiteralExpression())) + .build(); Expression conditionalNumber = Expression.newBuilder() - .setFunction( - Function.newBuilder() - .setFunctionName(QueryFunctionConstants.QUERY_FUNCTION_CONDITIONAL) - .addArguments(createStringLiteralValueExpression("true")) - .addArguments(createColumnExpression("Span.metrics.duration_millis")) - .addArguments(createNullNumberLiteralExpression())) - .build(); + .setFunction( + Function.newBuilder() + .setFunctionName(QueryFunctionConstants.QUERY_FUNCTION_CONDITIONAL) + .addArguments(createStringLiteralValueExpression("true")) + .addArguments(createColumnExpression("Span.metrics.duration_millis")) + .addArguments(createNullNumberLiteralExpression())) + .build(); QueryRequest queryRequest = QueryRequest.newBuilder() - .addSelection(conditionalString) - .addSelection(conditionalNumber) - .setLimit(15) - .build(); + .addSelection(conditionalString) + .addSelection(conditionalNumber) + .setLimit(15) + .build(); assertPQLQuery( queryRequest, @@ -1109,7 +1124,9 @@ private void assertPQLQuery(QueryRequest queryRequest, String expectedQuery) { QueryRequestToPinotSQLConverter converter = new QueryRequestToPinotSQLConverter(viewDefinition, new PinotFunctionConverter()); Entry statementToParam = - converter.toSQL(new ExecutionContext("__default", queryRequest), queryRequest, + converter.toSQL( + new ExecutionContext("__default", queryRequest), + queryRequest, createSelectionsFromQueryRequest(queryRequest)); PinotClient pinotClient = new PinotClient(connection); pinotClient.executeQuery(statementToParam.getKey(), statementToParam.getValue()); @@ -1119,14 +1136,21 @@ private void assertPQLQuery(QueryRequest queryRequest, String expectedQuery) { expectedQuery.toLowerCase(), statementCaptor.getValue().getQuery().toLowerCase()); } - private void assertExceptionOnPQLQuery(QueryRequest queryRequest, Class exceptionClass, + private void assertExceptionOnPQLQuery( + QueryRequest queryRequest, + Class exceptionClass, String expectedMessage) { QueryRequestToPinotSQLConverter converter = new QueryRequestToPinotSQLConverter(viewDefinition, new PinotFunctionConverter()); - Throwable exception = Assertions.assertThrows(exceptionClass, () -> converter - .toSQL(new ExecutionContext("__default", queryRequest), queryRequest, - createSelectionsFromQueryRequest(queryRequest))); + Throwable exception = + Assertions.assertThrows( + exceptionClass, + () -> + converter.toSQL( + new ExecutionContext("__default", queryRequest), + queryRequest, + createSelectionsFromQueryRequest(queryRequest))); String actualMessage = exception.getMessage(); Assertions.assertTrue(actualMessage.contains(expectedMessage)); diff --git a/query-service-impl/src/test/java/org/hypertrace/core/query/service/projection/ProjectionTransformationTest.java b/query-service-impl/src/test/java/org/hypertrace/core/query/service/projection/ProjectionTransformationTest.java index 38105b64..7f69d7de 100644 --- a/query-service-impl/src/test/java/org/hypertrace/core/query/service/projection/ProjectionTransformationTest.java +++ b/query-service-impl/src/test/java/org/hypertrace/core/query/service/projection/ProjectionTransformationTest.java @@ -404,7 +404,7 @@ void transformNullDefinedAttributes() { .build(); this.mockAttribute(PROJECTED_ATTRIBUTE_ID, this.attributeMetadata); - + expectedTransform = QueryRequest.newBuilder() .addSelection(createNullNumberLiteralExpression()) diff --git a/query-service/build.gradle.kts b/query-service/build.gradle.kts index 04b9d400..fc5d4d6b 100644 --- a/query-service/build.gradle.kts +++ b/query-service/build.gradle.kts @@ -18,10 +18,10 @@ dependencies { runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl:2.14.1") runtimeOnly("io.grpc:grpc-netty:1.36.1") constraints { - runtimeOnly("io.netty:netty-codec-http2:4.1.63.Final") { + runtimeOnly("io.netty:netty-codec-http2:4.1.68.Final") { because("https://snyk.io/vuln/SNYK-JAVA-IONETTY-1089809") } - runtimeOnly("io.netty:netty-handler-proxy:4.1.63.Final") { + runtimeOnly("io.netty:netty-handler-proxy:4.1.68.Final") { because("https://snyk.io/vuln/SNYK-JAVA-IONETTY-1089809") } } @@ -52,7 +52,7 @@ application { // Config for gw run to be able to run this locally. Just execute gw run here on Intellij or on the console. tasks.run { - jvmArgs = listOf("-Dbootstrap.config.uri=file:${projectDir}/src/main/resources/configs", "-Dservice.name=${project.name}") + jvmArgs = listOf("-Dbootstrap.config.uri=file:$projectDir/src/main/resources/configs", "-Dservice.name=${project.name}") } tasks.integrationTest { diff --git a/query-service/src/integrationTest/java/org/hypertrace/core/query/service/QueryServiceTestUtils.java b/query-service/src/integrationTest/java/org/hypertrace/core/query/service/QueryServiceTestUtils.java index 6a02db53..781756fc 100644 --- a/query-service/src/integrationTest/java/org/hypertrace/core/query/service/QueryServiceTestUtils.java +++ b/query-service/src/integrationTest/java/org/hypertrace/core/query/service/QueryServiceTestUtils.java @@ -11,8 +11,7 @@ public class QueryServiceTestUtils { public static Filter createFilter( - String columnName, Operator op, - ValueType valueType, Object valueObject) { + String columnName, Operator op, ValueType valueType, Object valueObject) { ColumnIdentifier startTimeColumn = ColumnIdentifier.newBuilder().setColumnName(columnName).build(); Expression lhs = Expression.newBuilder().setColumnIdentifier(startTimeColumn).build(); @@ -28,9 +27,8 @@ public static Filter createFilter( case STRING: value = Value.newBuilder(value).setString((String) valueObject).build(); } - LiteralConstant constant = - LiteralConstant.newBuilder().setValue(value).build(); + LiteralConstant constant = LiteralConstant.newBuilder().setValue(value).build(); Expression rhs = Expression.newBuilder().setLiteral(constant).build(); return Filter.newBuilder().setLhs(lhs).setOperator(op).setRhs(rhs).build(); } -} \ No newline at end of file +} diff --git a/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/BackendsQueries.java b/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/BackendsQueries.java index 73bf00c7..56e1b8c2 100644 --- a/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/BackendsQueries.java +++ b/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/BackendsQueries.java @@ -19,18 +19,29 @@ class BackendsQueries { /** * [ Select backend_id, backend_name, backend_protocol, COUNT(*) FROM backendEntityView WHERE * tenant_id = ? AND ( backend_id != ? AND start_time_millis >= ? AND start_time_millis < ? ) - * GROUP BY backend_id, backend_name, backend_protocol ORDER BY PERCENTILETDIGEST99(duration_millis) - * desc limit 10000=Params{integerParams={}, longParams={2=1612270796194, 3=1614689996194}, - * stringParams={0=__default, 1=null}, floatParams={}, doubleParams={}, byteStringParams={}} ] + * GROUP BY backend_id, backend_name, backend_protocol ORDER BY + * PERCENTILETDIGEST99(duration_millis) desc limit 10000=Params{integerParams={}, + * longParams={2=1612270796194, 3=1614689996194}, stringParams={0=__default, 1=null}, + * floatParams={}, doubleParams={}, byteStringParams={}} ] */ static QueryRequest buildQuery1() { Builder builder = QueryRequest.newBuilder(); ColumnIdentifier backendId = ColumnIdentifier.newBuilder().setColumnName("BACKEND.id").build(); - ColumnIdentifier backendName = ColumnIdentifier.newBuilder().setColumnName("BACKEND.name").setAlias("BACKEND.name").build(); - ColumnIdentifier backendType = ColumnIdentifier.newBuilder().setColumnName("BACKEND.type").setAlias("BACKEND.type").build(); - Function backendIdCountFunction = Function.newBuilder().addArguments( - Expression.newBuilder().setColumnIdentifier(backendId).build()).setFunctionName("COUNT") - .build(); + ColumnIdentifier backendName = + ColumnIdentifier.newBuilder() + .setColumnName("BACKEND.name") + .setAlias("BACKEND.name") + .build(); + ColumnIdentifier backendType = + ColumnIdentifier.newBuilder() + .setColumnName("BACKEND.type") + .setAlias("BACKEND.type") + .build(); + Function backendIdCountFunction = + Function.newBuilder() + .addArguments(Expression.newBuilder().setColumnIdentifier(backendId).build()) + .setFunctionName("COUNT") + .build(); builder.addSelection(Expression.newBuilder().setColumnIdentifier(backendId).build()); builder.addSelection(Expression.newBuilder().setColumnIdentifier(backendName).build()); @@ -38,12 +49,13 @@ static QueryRequest buildQuery1() { Filter filter1 = createFilter( - "BACKEND.startTime", Operator.GE, - ValueType.LONG, System.currentTimeMillis() - Duration.ofHours(1).toMillis()); + "BACKEND.startTime", + Operator.GE, + ValueType.LONG, + System.currentTimeMillis() - Duration.ofHours(1).toMillis()); Filter filter2 = - createFilter("BACKEND.startTime", Operator.LT, ValueType.LONG, System.currentTimeMillis()); - Filter filter3 = - createFilter("BACKEND.id", Operator.NEQ, ValueType.NULL_STRING, ""); + createFilter("BACKEND.startTime", Operator.LT, ValueType.LONG, System.currentTimeMillis()); + Filter filter3 = createFilter("BACKEND.id", Operator.NEQ, ValueType.NULL_STRING, ""); builder.setFilter( Filter.newBuilder() @@ -53,18 +65,24 @@ static QueryRequest buildQuery1() { .addChildFilter(filter3) .build()); - builder.addGroupBy( - Expression.newBuilder().setColumnIdentifier(backendId)); - builder.addGroupBy( - Expression.newBuilder().setColumnIdentifier(backendName)); - builder.addGroupBy( - Expression.newBuilder().setColumnIdentifier(backendType)); - Function backendDurationPercentileFunc = Function.newBuilder().addArguments( - Expression.newBuilder().setColumnIdentifier( - ColumnIdentifier.newBuilder().setColumnName("BACKEND.duration").build()).build()).setFunctionName("PERCENTILE99") - .build(); - OrderByExpression orderByExpression = OrderByExpression.newBuilder().setOrder(SortOrder.DESC).setExpression( - Expression.newBuilder().setFunction(backendDurationPercentileFunc).build()).build(); + builder.addGroupBy(Expression.newBuilder().setColumnIdentifier(backendId)); + builder.addGroupBy(Expression.newBuilder().setColumnIdentifier(backendName)); + builder.addGroupBy(Expression.newBuilder().setColumnIdentifier(backendType)); + Function backendDurationPercentileFunc = + Function.newBuilder() + .addArguments( + Expression.newBuilder() + .setColumnIdentifier( + ColumnIdentifier.newBuilder().setColumnName("BACKEND.duration").build()) + .build()) + .setFunctionName("PERCENTILE99") + .build(); + OrderByExpression orderByExpression = + OrderByExpression.newBuilder() + .setOrder(SortOrder.DESC) + .setExpression( + Expression.newBuilder().setFunction(backendDurationPercentileFunc).build()) + .build(); builder.addOrderBy(orderByExpression); builder.setLimit(10000); diff --git a/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/ExplorerQueries.java b/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/ExplorerQueries.java index 0a73896a..5a00dee1 100644 --- a/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/ExplorerQueries.java +++ b/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/ExplorerQueries.java @@ -17,33 +17,39 @@ class ExplorerQueries { /** - * [ Select dateTimeConvert(start_time_millis,?,?,?), COUNT(*) FROM spanEventView WHERE tenant_id = ? - * AND ( ( start_time_millis >= ? AND start_time_millis < ? ) AND ( api_boundary_type = ? AND api_id != ? ) ) - * GROUP BY dateTimeConvert(start_time_millis,?,?,?) limit 5000000=Params{integerParams={}, - * longParams={4=1612288800000, 5=1614686400000}, stringParams={0=1:MILLISECONDS:EPOCH, 1=1:MILLISECONDS:EPOCH, - * 2=21600:SECONDS, 3=__default, 6=ENTRY, 7=null, 8=1:MILLISECONDS:EPOCH, 9=1:MILLISECONDS:EPOCH, 10=21600:SECONDS}, + * [ Select dateTimeConvert(start_time_millis,?,?,?), COUNT(*) FROM spanEventView WHERE tenant_id + * = ? AND ( ( start_time_millis >= ? AND start_time_millis < ? ) AND ( api_boundary_type = ? AND + * api_id != ? ) ) GROUP BY dateTimeConvert(start_time_millis,?,?,?) limit + * 5000000=Params{integerParams={}, longParams={4=1612288800000, 5=1614686400000}, + * stringParams={0=1:MILLISECONDS:EPOCH, 1=1:MILLISECONDS:EPOCH, 2=21600:SECONDS, 3=__default, + * 6=ENTRY, 7=null, 8=1:MILLISECONDS:EPOCH, 9=1:MILLISECONDS:EPOCH, 10=21600:SECONDS}, * floatParams={}, doubleParams={}, byteStringParams={}} ] */ static QueryRequest buildQuery1() { Builder builder = QueryRequest.newBuilder(); - ColumnIdentifier apiTraceCalls = ColumnIdentifier.newBuilder().setColumnName("API_TRACE.calls").build(); - Function apiTraceCallsFunctionCount = Function.newBuilder().addArguments( - Expression.newBuilder().setColumnIdentifier(apiTraceCalls).build()) - .setFunctionName("COUNT").setAlias("COUNT_API_TRACE.calls_[]") - .build(); + ColumnIdentifier apiTraceCalls = + ColumnIdentifier.newBuilder().setColumnName("API_TRACE.calls").build(); + Function apiTraceCallsFunctionCount = + Function.newBuilder() + .addArguments(Expression.newBuilder().setColumnIdentifier(apiTraceCalls).build()) + .setFunctionName("COUNT") + .setAlias("COUNT_API_TRACE.calls_[]") + .build(); builder.addSelection(Expression.newBuilder().setFunction(apiTraceCallsFunctionCount)); Filter filter1 = createFilter( - "API_TRACE.startTime", Operator.GE, - ValueType.LONG, System.currentTimeMillis() - Duration.ofHours(1).toMillis()); + "API_TRACE.startTime", + Operator.GE, + ValueType.LONG, + System.currentTimeMillis() - Duration.ofHours(1).toMillis()); Filter filter2 = - createFilter("API_TRACE.startTime", Operator.LT, ValueType.LONG, System.currentTimeMillis()); + createFilter( + "API_TRACE.startTime", Operator.LT, ValueType.LONG, System.currentTimeMillis()); Filter filter3 = createFilter("API_TRACE.apiBoundaryType", Operator.EQ, ValueType.STRING, "ENTRY"); - Filter filter4 = - createFilter("API_TRACE.apiId", Operator.NEQ, ValueType.STRING, "null"); + Filter filter4 = createFilter("API_TRACE.apiId", Operator.NEQ, ValueType.STRING, "null"); builder.setFilter( Filter.newBuilder() @@ -54,16 +60,36 @@ static QueryRequest buildQuery1() { .addChildFilter(filter4) .build()); - Function dateTimeConvert = Function.newBuilder().setFunctionName("dateTimeConvert") - .addArguments(Expression.newBuilder().setColumnIdentifier( - ColumnIdentifier.newBuilder().setColumnName("API_TRACE.startTime").build()).build()) - .addArguments(Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setString("1:MILLISECONDS:EPOCH")).build()).build()) - .addArguments(Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setString("1:MILLISECONDS:EPOCH")).build()).build()) - .addArguments(Expression.newBuilder().setLiteral(LiteralConstant.newBuilder().setValue( - Value.newBuilder().setString("21600:SECONDS")).build()).build()) - .build(); + Function dateTimeConvert = + Function.newBuilder() + .setFunctionName("dateTimeConvert") + .addArguments( + Expression.newBuilder() + .setColumnIdentifier( + ColumnIdentifier.newBuilder().setColumnName("API_TRACE.startTime").build()) + .build()) + .addArguments( + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue(Value.newBuilder().setString("1:MILLISECONDS:EPOCH")) + .build()) + .build()) + .addArguments( + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue(Value.newBuilder().setString("1:MILLISECONDS:EPOCH")) + .build()) + .build()) + .addArguments( + Expression.newBuilder() + .setLiteral( + LiteralConstant.newBuilder() + .setValue(Value.newBuilder().setString("21600:SECONDS")) + .build()) + .build()) + .build(); builder.addGroupBy(Expression.newBuilder().setFunction(dateTimeConvert).build()); return builder.build(); } diff --git a/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/HTPinotQueriesTest.java b/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/HTPinotQueriesTest.java index 6c81bf1d..41965f3a 100644 --- a/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/HTPinotQueriesTest.java +++ b/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/HTPinotQueriesTest.java @@ -75,60 +75,64 @@ public class HTPinotQueriesTest { public static void setup() throws Exception { network = Network.newNetwork(); - kafkaZk = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka")) - .withNetwork(network) - .withNetworkAliases("kafka", "zookeeper") - .withStartupAttempts(CONTAINER_STARTUP_ATTEMPTS) - .waitingFor(Wait.forListeningPort()); + kafkaZk = + new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka")) + .withNetwork(network) + .withNetworkAliases("kafka", "zookeeper") + .withStartupAttempts(CONTAINER_STARTUP_ATTEMPTS) + .waitingFor(Wait.forListeningPort()); kafkaZk.start(); - pinotServiceManager = new GenericContainer<>( - DockerImageName.parse("hypertrace/pinot-servicemanager:main")) - .withNetwork(network) - .withNetworkAliases("pinot-controller", "pinot-server", "pinot-broker") - .withExposedPorts(8099) - .withExposedPorts(9000) - .dependsOn(kafkaZk) - .withStartupAttempts(CONTAINER_STARTUP_ATTEMPTS) - .waitingFor(Wait.forLogMessage(".*Completed schema installation.*", 1)) - .withLogConsumer(logConsumer); + pinotServiceManager = + new GenericContainer<>(DockerImageName.parse("hypertrace/pinot-servicemanager:main")) + .withNetwork(network) + .withNetworkAliases("pinot-controller", "pinot-server", "pinot-broker") + .withExposedPorts(8099) + .withExposedPorts(9000) + .dependsOn(kafkaZk) + .withStartupAttempts(CONTAINER_STARTUP_ATTEMPTS) + .waitingFor(Wait.forLogMessage(".*Completed schema installation.*", 1)) + .withLogConsumer(logConsumer); pinotServiceManager.start(); - mongo = new GenericContainer<>(DockerImageName.parse("hypertrace/mongodb:main")) - .withNetwork(network) - .withNetworkAliases("mongo") - .withExposedPorts(27017) - .withStartupAttempts(CONTAINER_STARTUP_ATTEMPTS) - .waitingFor(Wait.forLogMessage(".*waiting for connections on port 27017.*", 1)); + mongo = + new GenericContainer<>(DockerImageName.parse("hypertrace/mongodb:main")) + .withNetwork(network) + .withNetworkAliases("mongo") + .withExposedPorts(27017) + .withStartupAttempts(CONTAINER_STARTUP_ATTEMPTS) + .waitingFor(Wait.forLogMessage(".*waiting for connections on port 27017.*", 1)); mongo.start(); mongo.followOutput(logConsumer); - attributeService = new GenericContainer<>( - DockerImageName.parse("hypertrace/attribute-service:main")) - .withNetwork(network) - .withNetworkAliases("attribute-service") - .withEnv("MONGO_HOST", "mongo") - .withExposedPorts(9012) - .dependsOn(mongo) - .withStartupAttempts(CONTAINER_STARTUP_ATTEMPTS) - .waitingFor(Wait.forLogMessage(".*Started admin service on port: 9013.*", 1)); + attributeService = + new GenericContainer<>(DockerImageName.parse("hypertrace/attribute-service:main")) + .withNetwork(network) + .withNetworkAliases("attribute-service") + .withEnv("MONGO_HOST", "mongo") + .withExposedPorts(9012) + .dependsOn(mongo) + .withStartupAttempts(CONTAINER_STARTUP_ATTEMPTS) + .waitingFor(Wait.forLogMessage(".*Started admin service on port: 9013.*", 1)); attributeService.start(); attributeService.followOutput(logConsumer); - List topicsNames = List.of( - "enriched-structured-traces", - "raw-service-view-events", - "raw-trace-view-events", - "service-call-view-events", - "span-event-view", - "backend-entity-view-events", - "log-event-view", - "raw-logs"); + List topicsNames = + List.of( + "enriched-structured-traces", + "raw-service-view-events", + "raw-trace-view-events", + "service-call-view-events", + "span-event-view", + "backend-entity-view-events", + "log-event-view", + "raw-logs"); bootstrapServers = kafkaZk.getBootstrapServers(); - adminClient = AdminClient - .create(Map.of(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaZk.getBootstrapServers())); - List topics = topicsNames.stream().map(v -> new NewTopic(v, 1, (short) 1)) - .collect(Collectors.toList()); + adminClient = + AdminClient.create( + Map.of(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaZk.getBootstrapServers())); + List topics = + topicsNames.stream().map(v -> new NewTopic(v, 1, (short) 1)).collect(Collectors.toList()); adminClient.createTopics(topics); assertTrue(bootstrapConfig()); @@ -136,13 +140,11 @@ public static void setup() throws Exception { assertTrue(generateData()); LOG.info("Generate Data Complete"); - withEnvironmentVariable( - "PINOT_CONNECTION_TYPE", "broker") + withEnvironmentVariable("PINOT_CONNECTION_TYPE", "broker") .and("ZK_CONNECT_STR", "localhost:" + pinotServiceManager.getMappedPort(8099).toString()) .and("ATTRIBUTE_SERVICE_HOST_CONFIG", attributeService.getHost()) .and("ATTRIBUTE_SERVICE_PORT_CONFIG", attributeService.getMappedPort(9012).toString()) - .execute(() -> - IntegrationTestServerUtil.startServices(new String[] {"query-service"})); + .execute(() -> IntegrationTestServerUtil.startServices(new String[] {"query-service"})); Map map = Maps.newHashMap(); map.put("host", "localhost"); @@ -162,24 +164,35 @@ public static void shutdown() { } private static boolean bootstrapConfig() throws Exception { - GenericContainer bootstrapper = new GenericContainer<>( - DockerImageName.parse("hypertrace/config-bootstrapper:main")) - .withNetwork(network) - .dependsOn(attributeService) - .withEnv("MONGO_HOST", "mongo") - .withEnv("ATTRIBUTE_SERVICE_HOST_CONFIG", "attribute-service") - .withCommand("-c", "/app/resources/configs/config-bootstrapper/application.conf", "-C", "/app/resources/configs/config-bootstrapper/attribute-service", "--upgrade") - .withLogConsumer(logConsumer); + GenericContainer bootstrapper = + new GenericContainer<>(DockerImageName.parse("hypertrace/config-bootstrapper:main")) + .withNetwork(network) + .dependsOn(attributeService) + .withEnv("MONGO_HOST", "mongo") + .withEnv("ATTRIBUTE_SERVICE_HOST_CONFIG", "attribute-service") + .withCommand( + "-c", + "/app/resources/configs/config-bootstrapper/application.conf", + "-C", + "/app/resources/configs/config-bootstrapper/attribute-service", + "--upgrade") + .withLogConsumer(logConsumer); bootstrapper.start(); - ManagedChannel channel = ManagedChannelBuilder - .forAddress(attributeService.getHost(), attributeService.getMappedPort(9012)).usePlaintext() - .build(); + ManagedChannel channel = + ManagedChannelBuilder.forAddress( + attributeService.getHost(), attributeService.getMappedPort(9012)) + .usePlaintext() + .build(); AttributeServiceClient client = new AttributeServiceClient(channel); int retry = 0; while (Streams.stream( - client.findAttributes(TENANT_ID_MAP, AttributeMetadataFilter.getDefaultInstance())) - .collect(Collectors.toList()).size() == 0 && retry++ < 5) { + client.findAttributes( + TENANT_ID_MAP, AttributeMetadataFilter.getDefaultInstance())) + .collect(Collectors.toList()) + .size() + == 0 + && retry++ < 5) { Thread.sleep(2000); } channel.shutdown(); @@ -189,50 +202,58 @@ private static boolean bootstrapConfig() throws Exception { private static boolean generateData() throws Exception { // start view-gen service - GenericContainer viewGen = new GenericContainer( - DockerImageName.parse("hypertrace/hypertrace-view-generator:main")) - .withNetwork(network) - .dependsOn(kafkaZk) - .withEnv("KAFKA_BOOTSTRAP_SERVERS", "kafka:9092") - .withEnv("DEFAULT_KEY_SERDE", "org.hypertrace.core.kafkastreams.framework.serdes.AvroSerde") - .withEnv("DEFAULT_VALUE_SERDE", "org.hypertrace.core.kafkastreams.framework.serdes.AvroSerde") - .withEnv("NUM_STREAM_THREADS", "1") - .withStartupAttempts(CONTAINER_STARTUP_ATTEMPTS) - .waitingFor(Wait.forLogMessage(".* Started admin service on port: 8099.*", 1)); + GenericContainer viewGen = + new GenericContainer(DockerImageName.parse("hypertrace/hypertrace-view-generator:main")) + .withNetwork(network) + .dependsOn(kafkaZk) + .withEnv("KAFKA_BOOTSTRAP_SERVERS", "kafka:9092") + .withEnv( + "DEFAULT_KEY_SERDE", "org.hypertrace.core.kafkastreams.framework.serdes.AvroSerde") + .withEnv( + "DEFAULT_VALUE_SERDE", + "org.hypertrace.core.kafkastreams.framework.serdes.AvroSerde") + .withEnv("NUM_STREAM_THREADS", "1") + .withStartupAttempts(CONTAINER_STARTUP_ATTEMPTS) + .waitingFor(Wait.forLogMessage(".* Started admin service on port: 8099.*", 1)); viewGen.start(); viewGen.followOutput(logConsumer); // produce data - SpecificDatumReader datumReader = new SpecificDatumReader<>( - StructuredTrace.getClassSchema()); + SpecificDatumReader datumReader = + new SpecificDatumReader<>(StructuredTrace.getClassSchema()); - DataFileReader dfrStructuredTrace = new DataFileReader<>( - new File(Thread.currentThread() - .getContextClassLoader() - .getResource("StructuredTrace-Hotrod.avro").getPath()), - datumReader); + DataFileReader dfrStructuredTrace = + new DataFileReader<>( + new File( + Thread.currentThread() + .getContextClassLoader() + .getResource("StructuredTrace-Hotrod.avro") + .getPath()), + datumReader); StructuredTrace trace = dfrStructuredTrace.next(); dfrStructuredTrace.close(); updateTraceTimeStamp(trace); - KafkaProducer producer = new KafkaProducer<>( - ImmutableMap.of( - ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, - ProducerConfig.CLIENT_ID_CONFIG, UUID.randomUUID().toString() - ), - new StringSerializer(), - new AvroSerde().serializer() - ); + KafkaProducer producer = + new KafkaProducer<>( + ImmutableMap.of( + ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, + bootstrapServers, + ProducerConfig.CLIENT_ID_CONFIG, + UUID.randomUUID().toString()), + new StringSerializer(), + new AvroSerde().serializer()); producer.send(new ProducerRecord<>("enriched-structured-traces", "", trace)).get(); - Map endOffSetMap = Map.of( - "raw-service-view-events", 13L, - "backend-entity-view-events", 11L, - "raw-trace-view-events", 1L, - "service-call-view-events", 27L, - "span-event-view", 50L, - "log-event-view", 0L); + Map endOffSetMap = + Map.of( + "raw-service-view-events", 13L, + "backend-entity-view-events", 11L, + "raw-trace-view-events", 1L, + "service-call-view-events", 27L, + "span-event-view", 50L, + "log-event-view", 0L); int retry = 0; while (!areMessagesConsumed(endOffSetMap) && retry++ < 5) { Thread.sleep(2000); @@ -244,8 +265,8 @@ private static boolean generateData() throws Exception { } private static boolean areMessagesConsumed(Map endOffSetMap) throws Exception { - ListConsumerGroupOffsetsResult consumerGroupOffsetsResult = adminClient - .listConsumerGroupOffsets(""); + ListConsumerGroupOffsetsResult consumerGroupOffsetsResult = + adminClient.listConsumerGroupOffsets(""); Map offsetAndMetadataMap = consumerGroupOffsetsResult.partitionsToOffsetAndMetadata().get(); if (offsetAndMetadataMap.size() < 6) { @@ -263,30 +284,36 @@ private static void updateTraceTimeStamp(StructuredTrace trace) { trace.getEventList().forEach(e -> e.setStartTimeMillis(e.getStartTimeMillis() + delta)); trace.getEventList().forEach(e -> e.setEndTimeMillis(e.getEndTimeMillis() + delta)); // updates edges - trace.getEntityEdgeList() + trace + .getEntityEdgeList() .forEach(edge -> edge.setStartTimeMillis(edge.getStartTimeMillis() + delta)); - trace.getEntityEdgeList() + trace + .getEntityEdgeList() .forEach(edge -> edge.setEndTimeMillis(edge.getEndTimeMillis() + delta)); - trace.getEventEdgeList() + trace + .getEventEdgeList() .forEach(edge -> edge.setStartTimeMillis(edge.getStartTimeMillis() + delta)); - trace.getEventEdgeList() + trace + .getEventEdgeList() .forEach(edge -> edge.setEndTimeMillis(edge.getEndTimeMillis() + delta)); - trace.getEntityEventEdgeList() + trace + .getEntityEventEdgeList() .forEach(edge -> edge.setStartTimeMillis(edge.getStartTimeMillis() + delta)); - trace.getEntityEventEdgeList() + trace + .getEntityEventEdgeList() .forEach(edge -> edge.setEndTimeMillis(edge.getEndTimeMillis() + delta)); } @Test public void testServicesQueries() { LOG.info("Services queries"); - Iterator itr = queryServiceClient.executeQuery( - ServicesQueries.buildQuery1(), TENANT_ID_MAP, 10000); + Iterator itr = + queryServiceClient.executeQuery(ServicesQueries.buildQuery1(), TENANT_ID_MAP, 10000); List list = Streams.stream(itr).collect(Collectors.toList()); List rows = list.get(0).getRowList(); assertEquals(4, rows.size()); - List serviceNames = new ArrayList<>( - Arrays.asList("frontend", "driver", "route", "customer")); + List serviceNames = + new ArrayList<>(Arrays.asList("frontend", "driver", "route", "customer")); rows.forEach(row -> serviceNames.remove(row.getColumn(1).getString())); assertTrue(serviceNames.isEmpty()); } @@ -294,8 +321,8 @@ public void testServicesQueries() { @Test public void testBackendsQueries() { LOG.info("Backends queries"); - Iterator itr = queryServiceClient.executeQuery( - BackendsQueries.buildQuery1(), TENANT_ID_MAP, 10000); + Iterator itr = + queryServiceClient.executeQuery(BackendsQueries.buildQuery1(), TENANT_ID_MAP, 10000); List list = Streams.stream(itr).collect(Collectors.toList()); List rows = list.get(0).getRowList(); assertEquals(1, rows.size()); @@ -307,12 +334,12 @@ public void testBackendsQueries() { @Test public void testExplorerQueries() { LOG.info("Explorer queries"); - Iterator itr = queryServiceClient.executeQuery( - ExplorerQueries.buildQuery1(), TENANT_ID_MAP, 10000); + Iterator itr = + queryServiceClient.executeQuery(ExplorerQueries.buildQuery1(), TENANT_ID_MAP, 10000); List list = Streams.stream(itr).collect(Collectors.toList()); List rows = list.get(0).getRowList(); assertEquals(1, rows.size()); // COUNT_API_TRACE.calls_[] is 13 assertEquals("13", rows.get(0).getColumn(1).getString()); } -} \ No newline at end of file +} diff --git a/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/ServicesQueries.java b/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/ServicesQueries.java index 0e411c70..d86457a5 100644 --- a/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/ServicesQueries.java +++ b/query-service/src/integrationTest/java/org/hypertrace/core/query/service/htqueries/ServicesQueries.java @@ -17,19 +17,25 @@ class ServicesQueries { /** - * [ Select service_id, service_name, COUNT(*) FROM rawServiceView - * WHERE tenant_id = ? AND ( service_id != ? AND start_time_millis >= ? AND start_time_millis < ? - * ) GROUP BY service_id, service_name ORDER BY PERCENTILETDIGEST99(duration_millis) desc limit + * [ Select service_id, service_name, COUNT(*) FROM rawServiceView WHERE tenant_id = ? AND ( + * service_id != ? AND start_time_millis >= ? AND start_time_millis < ? ) GROUP BY service_id, + * service_name ORDER BY PERCENTILETDIGEST99(duration_millis) desc limit * 10000=Params{integerParams={}, longParams={2=1612271838043, 3=1614691038043}, * stringParams={0=__default, 1=null}, floatParams={}, doubleParams={}, byteStringParams={}} ] */ static QueryRequest buildQuery1() { Builder builder = QueryRequest.newBuilder(); ColumnIdentifier serviceId = ColumnIdentifier.newBuilder().setColumnName("SERVICE.id").build(); - ColumnIdentifier serviceName = ColumnIdentifier.newBuilder().setColumnName("SERVICE.name").setAlias("SERVICE.name").build(); - Function serviceIdFunction = Function.newBuilder().addArguments( - Expression.newBuilder().setColumnIdentifier(serviceId).build()).setFunctionName("COUNT") - .build(); + ColumnIdentifier serviceName = + ColumnIdentifier.newBuilder() + .setColumnName("SERVICE.name") + .setAlias("SERVICE.name") + .build(); + Function serviceIdFunction = + Function.newBuilder() + .addArguments(Expression.newBuilder().setColumnIdentifier(serviceId).build()) + .setFunctionName("COUNT") + .build(); builder.addSelection(Expression.newBuilder().setColumnIdentifier(serviceId).build()); builder.addSelection(Expression.newBuilder().setColumnIdentifier(serviceName).build()); @@ -37,12 +43,13 @@ static QueryRequest buildQuery1() { Filter filter1 = createFilter( - "SERVICE.startTime", Operator.GE, - ValueType.LONG, System.currentTimeMillis() - Duration.ofHours(1).toMillis()); + "SERVICE.startTime", + Operator.GE, + ValueType.LONG, + System.currentTimeMillis() - Duration.ofHours(1).toMillis()); Filter filter2 = - createFilter("SERVICE.startTime", Operator.LT, ValueType.LONG, System.currentTimeMillis()); - Filter filter3 = - createFilter("SERVICE.id", Operator.NEQ, ValueType.NULL_STRING, ""); + createFilter("SERVICE.startTime", Operator.LT, ValueType.LONG, System.currentTimeMillis()); + Filter filter3 = createFilter("SERVICE.id", Operator.NEQ, ValueType.NULL_STRING, ""); builder.setFilter( Filter.newBuilder() @@ -52,16 +59,23 @@ static QueryRequest buildQuery1() { .addChildFilter(filter3) .build()); - - builder.addGroupBy( - Expression.newBuilder().setColumnIdentifier(serviceId)); - builder.addGroupBy( - Expression.newBuilder().setColumnIdentifier(serviceName)); - Function serviceDurationPercentileFunc = Function.newBuilder().addArguments( - Expression.newBuilder().setColumnIdentifier(ColumnIdentifier.newBuilder().setColumnName("SERVICE.duration").build()).build()).setFunctionName("PERCENTILE99") - .build(); - OrderByExpression orderByExpression = OrderByExpression.newBuilder().setOrder(SortOrder.DESC).setExpression( - Expression.newBuilder().setFunction(serviceDurationPercentileFunc).build()).build(); + builder.addGroupBy(Expression.newBuilder().setColumnIdentifier(serviceId)); + builder.addGroupBy(Expression.newBuilder().setColumnIdentifier(serviceName)); + Function serviceDurationPercentileFunc = + Function.newBuilder() + .addArguments( + Expression.newBuilder() + .setColumnIdentifier( + ColumnIdentifier.newBuilder().setColumnName("SERVICE.duration").build()) + .build()) + .setFunctionName("PERCENTILE99") + .build(); + OrderByExpression orderByExpression = + OrderByExpression.newBuilder() + .setOrder(SortOrder.DESC) + .setExpression( + Expression.newBuilder().setFunction(serviceDurationPercentileFunc).build()) + .build(); builder.addOrderBy(orderByExpression); builder.setLimit(10000);