-
Notifications
You must be signed in to change notification settings - Fork 6
chore(entity-query-service): better integration tests for update API #128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,18 +9,21 @@ | |
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
import com.google.common.collect.Lists; | ||
import com.google.protobuf.LazyStringList; | ||
import com.typesafe.config.Config; | ||
import com.typesafe.config.ConfigFactory; | ||
import io.grpc.Channel; | ||
import io.grpc.ManagedChannel; | ||
import io.grpc.ManagedChannelBuilder; | ||
import java.time.Instant; | ||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.UUID; | ||
import java.util.stream.Collectors; | ||
import org.hypertrace.core.documentstore.Datastore; | ||
import org.hypertrace.core.documentstore.DatastoreProvider; | ||
import org.hypertrace.core.grpcutils.client.GrpcClientRequestContextUtil; | ||
|
@@ -31,6 +34,7 @@ | |
import org.hypertrace.entity.constants.v1.ServiceAttribute; | ||
import org.hypertrace.entity.data.service.client.EntityDataServiceClient; | ||
import org.hypertrace.entity.data.service.v1.AttributeValue; | ||
import org.hypertrace.entity.data.service.v1.AttributeValueList; | ||
import org.hypertrace.entity.data.service.v1.Entity; | ||
import org.hypertrace.entity.data.service.v1.Value; | ||
import org.hypertrace.entity.query.service.client.EntityQueryServiceClient; | ||
|
@@ -94,6 +98,7 @@ public class EntityQueryServiceTest { | |
// attributes defined in application.conf in attribute map | ||
private static final String API_DISCOVERY_STATE_ATTR = "API.apiDiscoveryState"; | ||
private static final String API_HTTP_METHOD_ATTR = "API.httpMethod"; | ||
private static final String API_LABELS_ATTR = "API.labels"; | ||
private static final int CONTAINER_STARTUP_ATTEMPTS = 5; | ||
private static GenericContainer<?> mongo; | ||
|
||
|
@@ -484,6 +489,11 @@ public void testBulkUpdate() { | |
.setTenantId(TENANT_ID) | ||
.setEntityType(EntityType.API.name()) | ||
.setEntityName("api1") | ||
.putAttributes( | ||
apiAttributesMap.get(API_DISCOVERY_STATE_ATTR), createAttribute("DISCOVERED")) | ||
.putAttributes(apiAttributesMap.get(API_HTTP_METHOD_ATTR), createAttribute("GET")) | ||
.putAttributes( | ||
apiAttributesMap.get(API_LABELS_ATTR), createArrayAttribute(List.of("Label1"))) | ||
.putIdentifyingAttributes( | ||
EntityConstants.getValue(ServiceAttribute.SERVICE_ATTRIBUTE_ID), | ||
createAttribute(SERVICE_ID)) | ||
|
@@ -492,17 +502,17 @@ public void testBulkUpdate() { | |
.putIdentifyingAttributes( | ||
EntityConstants.getValue(ApiAttribute.API_ATTRIBUTE_API_TYPE), | ||
createAttribute(API_TYPE)); | ||
apiEntityBuilder1 | ||
.putAttributes( | ||
apiAttributesMap.get(API_DISCOVERY_STATE_ATTR), createAttribute("DISCOVERED")) | ||
.putAttributes(apiAttributesMap.get(API_HTTP_METHOD_ATTR), createAttribute("GET")); | ||
|
||
Entity entity1 = entityDataServiceClient.upsert(apiEntityBuilder1.build()); | ||
|
||
Entity.Builder apiEntityBuilder2 = | ||
Entity.newBuilder() | ||
.setTenantId(TENANT_ID) | ||
.setEntityType(EntityType.API.name()) | ||
.setEntityName("api2") | ||
.putAttributes( | ||
apiAttributesMap.get(API_DISCOVERY_STATE_ATTR), createAttribute("UNDER_DISCOVERY")) | ||
.putAttributes(apiAttributesMap.get(API_HTTP_METHOD_ATTR), createAttribute("GET")) | ||
.putIdentifyingAttributes( | ||
EntityConstants.getValue(ServiceAttribute.SERVICE_ATTRIBUTE_ID), | ||
createAttribute(SERVICE_ID)) | ||
|
@@ -511,43 +521,44 @@ public void testBulkUpdate() { | |
.putIdentifyingAttributes( | ||
EntityConstants.getValue(ApiAttribute.API_ATTRIBUTE_API_TYPE), | ||
createAttribute(API_TYPE)); | ||
apiEntityBuilder2 | ||
.putAttributes( | ||
apiAttributesMap.get(API_DISCOVERY_STATE_ATTR), createAttribute("UNDER_DISCOVERY")) | ||
.putAttributes(apiAttributesMap.get(API_HTTP_METHOD_ATTR), createAttribute("GET")); | ||
Entity entity2 = entityDataServiceClient.upsert(apiEntityBuilder2.build()); | ||
|
||
// create BulkUpdate request | ||
UpdateOperation update1 = | ||
UpdateOperation apiDiscoveryStateUpdateOperation = | ||
UpdateOperation.newBuilder() | ||
.setSetAttribute( | ||
SetAttribute.newBuilder() | ||
.setAttribute( | ||
ColumnIdentifier.newBuilder().setColumnName(API_DISCOVERY_STATE_ATTR)) | ||
.setValue( | ||
LiteralConstant.newBuilder() | ||
.setValue( | ||
org.hypertrace.entity.query.service.v1.Value.newBuilder() | ||
.setString("DISCOVERED")))) | ||
.setValue(createLiteral("DISCOVERED"))) | ||
.build(); | ||
UpdateOperation update2 = | ||
UpdateOperation httpMethodUpdateOperation = | ||
UpdateOperation.newBuilder() | ||
.setSetAttribute( | ||
SetAttribute.newBuilder() | ||
.setAttribute(ColumnIdentifier.newBuilder().setColumnName(API_HTTP_METHOD_ATTR)) | ||
.setValue( | ||
LiteralConstant.newBuilder() | ||
.setValue( | ||
org.hypertrace.entity.query.service.v1.Value.newBuilder() | ||
.setString("POST")))) | ||
.setValue(createLiteral("POST"))) | ||
.build(); | ||
UpdateOperation apiLabelsUpdateOperation = | ||
UpdateOperation.newBuilder() | ||
.setSetAttribute( | ||
SetAttribute.newBuilder() | ||
.setAttribute(ColumnIdentifier.newBuilder().setColumnName(API_LABELS_ATTR)) | ||
.setValue(createLiteral(List.of("Label1", "Label2")))) | ||
.build(); | ||
|
||
EntityUpdateInfo updateInfo1 = | ||
EntityUpdateInfo.newBuilder().addUpdateOperation(update2).build(); | ||
EntityUpdateInfo.newBuilder() | ||
.addUpdateOperation(httpMethodUpdateOperation) | ||
.addUpdateOperation(apiLabelsUpdateOperation) | ||
.build(); | ||
EntityUpdateInfo updateInfo2 = | ||
EntityUpdateInfo.newBuilder() | ||
.addUpdateOperation(update1) | ||
.addUpdateOperation(update2) | ||
.addUpdateOperation(apiDiscoveryStateUpdateOperation) | ||
.addUpdateOperation(httpMethodUpdateOperation) | ||
.addUpdateOperation(apiLabelsUpdateOperation) | ||
.build(); | ||
|
||
BulkEntityUpdateRequest bulkUpdateRequest = | ||
BulkEntityUpdateRequest.newBuilder() | ||
.setEntityType(EntityType.API.name()) | ||
|
@@ -563,30 +574,45 @@ public void testBulkUpdate() { | |
.setEntityType(EntityType.API.name()) | ||
.addSelection(createExpression(API_DISCOVERY_STATE_ATTR)) | ||
.addSelection(createExpression(API_HTTP_METHOD_ATTR)) | ||
.addSelection(createExpression(API_LABELS_ATTR)) | ||
.build(); | ||
|
||
Iterator<ResultSetChunk> resultSetChunkIterator = | ||
GrpcClientRequestContextUtil.executeWithHeadersContext( | ||
HEADERS, () -> entityQueryServiceClient.execute(entityQueryRequest)); | ||
|
||
List<String> values = new ArrayList<>(); | ||
List<Object> values = new ArrayList<>(); | ||
|
||
while (resultSetChunkIterator.hasNext()) { | ||
ResultSetChunk chunk = resultSetChunkIterator.next(); | ||
|
||
for (Row row : chunk.getRowList()) { | ||
for (int i = 0; i < row.getColumnCount(); i++) { | ||
String value = row.getColumnList().get(i).getString(); | ||
values.add(value); | ||
org.hypertrace.entity.query.service.v1.Value value = row.getColumnList().get(i); | ||
switch (value.getValueType()) { | ||
case STRING: | ||
values.add(value.getString()); | ||
continue; | ||
case STRING_ARRAY: | ||
values.add(value.getStringArrayList()); | ||
continue; | ||
default: | ||
} | ||
} | ||
} | ||
} | ||
|
||
assertEquals(4, values.size()); | ||
assertEquals(6, values.size()); | ||
assertEquals("DISCOVERED", values.get(0)); | ||
assertEquals("POST", values.get(1)); | ||
assertEquals("DISCOVERED", values.get(2)); | ||
assertEquals("POST", values.get(3)); | ||
assertListEquals( | ||
List.of("Label1", "Label2"), | ||
((LazyStringList) values.get(2)).stream().collect(Collectors.toUnmodifiableList())); | ||
assertEquals("DISCOVERED", values.get(3)); | ||
assertEquals("POST", values.get(4)); | ||
assertListEquals( | ||
List.of("Label1", "Label2"), | ||
((LazyStringList) values.get(5)).stream().collect(Collectors.toUnmodifiableList())); | ||
} | ||
|
||
@Nested | ||
|
@@ -677,6 +703,34 @@ private AttributeValue createAttribute(String name) { | |
return AttributeValue.newBuilder().setValue(Value.newBuilder().setString(name).build()).build(); | ||
} | ||
|
||
private AttributeValue createArrayAttribute(Collection<String> values) { | ||
return AttributeValue.newBuilder() | ||
.setValueList( | ||
AttributeValueList.newBuilder() | ||
.addAllValues( | ||
values.stream().map(this::createAttribute).collect(Collectors.toList())) | ||
.build()) | ||
.build(); | ||
} | ||
|
||
private LiteralConstant createLiteral(String value) { | ||
return LiteralConstant.newBuilder() | ||
.setValue( | ||
org.hypertrace.entity.query.service.v1.Value.newBuilder() | ||
.setString(value) | ||
.setValueType(ValueType.STRING)) | ||
.build(); | ||
} | ||
|
||
private LiteralConstant createLiteral(Collection<String> values) { | ||
return LiteralConstant.newBuilder() | ||
.setValue( | ||
org.hypertrace.entity.query.service.v1.Value.newBuilder() | ||
.addAllStringArray(values) | ||
.setValueType(ValueType.STRING_ARRAY)) | ||
.build(); | ||
} | ||
|
||
private Entity.Builder createApiEntity(String serviceId, String apiName, String apiType) { | ||
return Entity.newBuilder() | ||
.setTenantId(TENANT_ID) | ||
|
@@ -734,4 +788,10 @@ private static Map<String, Map<String, String>> getAttributesMap() { | |
|
||
return attributesMap; | ||
} | ||
|
||
private <T> void assertListEquals(List<T> expected, List<T> actual) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why can't this just use assertEquals? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried that. It wasn't working with the basic Didn't spend much time on why it wasn't working There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, worth figuring out - something's off here. This check for example doesn't assert that their order matches, which is part of list equality. |
||
assertEquals(expected.size(), actual.size()); | ||
assertTrue(actual.containsAll(expected)); | ||
assertTrue(expected.containsAll(actual)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add an integer to the integration test, too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't support updating INT yet via EQS update APIs. Planning to add support for that in a separate PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't? maybe I'm misunderstanding or looking in the wrong spot, but it sure looks like we do - unless it's in the API but not the implementation?
->
->
->
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, the implementation only has long in its switch, not int. That's really confusing, but is actually right (other than the fact that it should yell loudly and not have it in its interface)- entities only have long fields, not int.
...and just to clarify further, because this is a complete mess - Entity the object returned by EDS can actually hold both int and long, and Row the EQS response can hold both (and those two don't match WRT certain other data types 😢 ), but our attribute schema, which represents the entity field data types does not have an int type - and our attribute schema should be the source of truth here.
So tl;dr - we shouldn't add support for int, but could we add long to the test?