mirror of
https://github.com/datahub-project/datahub.git
synced 2025-08-16 13:16:52 +00:00
fix(java-sdk): custom properties patch client (#11984)
This commit is contained in:
parent
337f2b95f5
commit
02198f7b27
@ -17,10 +17,16 @@ public class CustomPropertiesPatchBuilder<T extends AbstractMultiFieldPatchBuild
|
|||||||
public static final String CUSTOM_PROPERTIES_BASE_PATH = "/customProperties";
|
public static final String CUSTOM_PROPERTIES_BASE_PATH = "/customProperties";
|
||||||
|
|
||||||
private final T parent;
|
private final T parent;
|
||||||
private final List<ImmutableTriple<String, String, JsonNode>> operations = new ArrayList<>();
|
private final List<ImmutableTriple<String, String, JsonNode>> operations;
|
||||||
|
|
||||||
public CustomPropertiesPatchBuilder(T parentBuilder) {
|
public CustomPropertiesPatchBuilder(T parentBuilder) {
|
||||||
this.parent = parentBuilder;
|
this.parent = parentBuilder;
|
||||||
|
if (parentBuilder != null) {
|
||||||
|
// If a parent builder is provided, we use the same path operations list.
|
||||||
|
this.operations = parentBuilder.getPathValues();
|
||||||
|
} else {
|
||||||
|
this.operations = new ArrayList<>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,9 +78,4 @@ public class CustomPropertiesPatchBuilder<T extends AbstractMultiFieldPatchBuild
|
|||||||
public T getParent() {
|
public T getParent() {
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ImmutableTriple<String, String, JsonNode>> getSubPaths() {
|
|
||||||
return operations;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,10 @@ import static com.fasterxml.jackson.databind.node.JsonNodeFactory.instance;
|
|||||||
import static com.linkedin.metadata.Constants.DATA_FLOW_ENTITY_NAME;
|
import static com.linkedin.metadata.Constants.DATA_FLOW_ENTITY_NAME;
|
||||||
import static com.linkedin.metadata.Constants.DATA_FLOW_INFO_ASPECT_NAME;
|
import static com.linkedin.metadata.Constants.DATA_FLOW_INFO_ASPECT_NAME;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import com.linkedin.common.TimeStamp;
|
import com.linkedin.common.TimeStamp;
|
||||||
import com.linkedin.metadata.aspect.patch.PatchOperationType;
|
import com.linkedin.metadata.aspect.patch.PatchOperationType;
|
||||||
import com.linkedin.metadata.aspect.patch.builder.subtypesupport.CustomPropertiesPatchBuilderSupport;
|
import com.linkedin.metadata.aspect.patch.builder.subtypesupport.CustomPropertiesPatchBuilderSupport;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -87,28 +85,23 @@ public class DataFlowInfoPatchBuilder
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DataFlowInfoPatchBuilder setLastModified(@Nullable TimeStamp lastModified) {
|
public DataFlowInfoPatchBuilder setLastModified(@Nullable TimeStamp lastModified) {
|
||||||
|
ObjectNode lastModifiedNode = instance.objectNode();
|
||||||
if (lastModified == null) {
|
if (lastModified == null) {
|
||||||
pathValues.add(
|
pathValues.add(
|
||||||
ImmutableTriple.of(
|
ImmutableTriple.of(
|
||||||
PatchOperationType.REMOVE.getValue(), BASE_PATH + LAST_MODIFIED_KEY, null));
|
PatchOperationType.REMOVE.getValue(), BASE_PATH + LAST_MODIFIED_KEY, null));
|
||||||
|
} else {
|
||||||
|
lastModifiedNode.put(TIME_KEY, lastModified.getTime());
|
||||||
|
if (lastModified.getActor() != null) {
|
||||||
|
lastModifiedNode.put(ACTOR_KEY, lastModified.getActor().toString());
|
||||||
|
}
|
||||||
|
pathValues.add(
|
||||||
|
ImmutableTriple.of(
|
||||||
|
PatchOperationType.ADD.getValue(), BASE_PATH + LAST_MODIFIED_KEY, lastModifiedNode));
|
||||||
}
|
}
|
||||||
ObjectNode lastModifiedNode = instance.objectNode();
|
|
||||||
lastModifiedNode.put(TIME_KEY, lastModified.getTime());
|
|
||||||
if (lastModified.getActor() != null) {
|
|
||||||
lastModifiedNode.put(ACTOR_KEY, lastModified.getActor().toString());
|
|
||||||
}
|
|
||||||
pathValues.add(
|
|
||||||
ImmutableTriple.of(
|
|
||||||
PatchOperationType.ADD.getValue(), BASE_PATH + LAST_MODIFIED_KEY, lastModifiedNode));
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<ImmutableTriple<String, String, JsonNode>> getPathValues() {
|
|
||||||
pathValues.addAll(customPropertiesPatchBuilder.getSubPaths());
|
|
||||||
return pathValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getAspectName() {
|
protected String getAspectName() {
|
||||||
return DATA_FLOW_INFO_ASPECT_NAME;
|
return DATA_FLOW_INFO_ASPECT_NAME;
|
||||||
|
@ -4,13 +4,11 @@ import static com.fasterxml.jackson.databind.node.JsonNodeFactory.instance;
|
|||||||
import static com.linkedin.metadata.Constants.DATA_JOB_ENTITY_NAME;
|
import static com.linkedin.metadata.Constants.DATA_JOB_ENTITY_NAME;
|
||||||
import static com.linkedin.metadata.Constants.DATA_JOB_INFO_ASPECT_NAME;
|
import static com.linkedin.metadata.Constants.DATA_JOB_INFO_ASPECT_NAME;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import com.linkedin.common.TimeStamp;
|
import com.linkedin.common.TimeStamp;
|
||||||
import com.linkedin.common.urn.DataFlowUrn;
|
import com.linkedin.common.urn.DataFlowUrn;
|
||||||
import com.linkedin.metadata.aspect.patch.PatchOperationType;
|
import com.linkedin.metadata.aspect.patch.PatchOperationType;
|
||||||
import com.linkedin.metadata.aspect.patch.builder.subtypesupport.CustomPropertiesPatchBuilderSupport;
|
import com.linkedin.metadata.aspect.patch.builder.subtypesupport.CustomPropertiesPatchBuilderSupport;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -113,12 +111,6 @@ public class DataJobInfoPatchBuilder extends AbstractMultiFieldPatchBuilder<Data
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<ImmutableTriple<String, String, JsonNode>> getPathValues() {
|
|
||||||
pathValues.addAll(customPropertiesPatchBuilder.getSubPaths());
|
|
||||||
return pathValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getAspectName() {
|
protected String getAspectName() {
|
||||||
return DATA_JOB_INFO_ASPECT_NAME;
|
return DATA_JOB_INFO_ASPECT_NAME;
|
||||||
|
@ -4,10 +4,8 @@ import static com.fasterxml.jackson.databind.node.JsonNodeFactory.instance;
|
|||||||
import static com.linkedin.metadata.Constants.DATASET_ENTITY_NAME;
|
import static com.linkedin.metadata.Constants.DATASET_ENTITY_NAME;
|
||||||
import static com.linkedin.metadata.Constants.DATASET_PROPERTIES_ASPECT_NAME;
|
import static com.linkedin.metadata.Constants.DATASET_PROPERTIES_ASPECT_NAME;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.linkedin.metadata.aspect.patch.PatchOperationType;
|
import com.linkedin.metadata.aspect.patch.PatchOperationType;
|
||||||
import com.linkedin.metadata.aspect.patch.builder.subtypesupport.CustomPropertiesPatchBuilderSupport;
|
import com.linkedin.metadata.aspect.patch.builder.subtypesupport.CustomPropertiesPatchBuilderSupport;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -116,12 +114,6 @@ public class DatasetPropertiesPatchBuilder
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<ImmutableTriple<String, String, JsonNode>> getPathValues() {
|
|
||||||
pathValues.addAll(customPropertiesPatchBuilder.getSubPaths());
|
|
||||||
return pathValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getAspectName() {
|
protected String getAspectName() {
|
||||||
return DATASET_PROPERTIES_ASPECT_NAME;
|
return DATASET_PROPERTIES_ASPECT_NAME;
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package com.linkedin.metadata.aspect.patch.builder.subtypesupport;
|
package com.linkedin.metadata.aspect.patch.builder.subtypesupport;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.linkedin.metadata.aspect.patch.builder.AbstractMultiFieldPatchBuilder;
|
import com.linkedin.metadata.aspect.patch.builder.AbstractMultiFieldPatchBuilder;
|
||||||
import java.util.List;
|
|
||||||
import org.apache.commons.lang3.tuple.ImmutableTriple;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for supporting intermediate subtypes when constructing a patch for an aspect that includes
|
* Used for supporting intermediate subtypes when constructing a patch for an aspect that includes
|
||||||
@ -15,10 +12,4 @@ public interface IntermediatePatchBuilder<T extends AbstractMultiFieldPatchBuild
|
|||||||
|
|
||||||
/** Convenience method to return parent patch builder in functional callstack */
|
/** Convenience method to return parent patch builder in functional callstack */
|
||||||
T getParent();
|
T getParent();
|
||||||
|
|
||||||
/**
|
|
||||||
* Exposes subpath values to parent patch builder in Op, Path, Value triples. Should usually only
|
|
||||||
* be called by the parent patch builder class when constructing the path values.
|
|
||||||
*/
|
|
||||||
List<ImmutableTriple<String, String, JsonNode>> getSubPaths();
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,280 @@
|
|||||||
|
package com.linkedin.metadata.aspect.patch.builder;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
import static org.testng.Assert.assertNull;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.linkedin.common.TimeStamp;
|
||||||
|
import com.linkedin.common.urn.Urn;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.apache.commons.lang3.tuple.ImmutableTriple;
|
||||||
|
import org.testng.annotations.BeforeMethod;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
public class DataFlowInfoPatchBuilderTest {
|
||||||
|
|
||||||
|
private TestableDataFlowInfoPatchBuilder builder;
|
||||||
|
private static final String TEST_URN = "urn:li:dataFlow:(test,flow1,PROD)";
|
||||||
|
|
||||||
|
// Test helper class to expose protected method
|
||||||
|
private static class TestableDataFlowInfoPatchBuilder extends DataFlowInfoPatchBuilder {
|
||||||
|
public List<ImmutableTriple<String, String, JsonNode>> getTestPathValues() {
|
||||||
|
return getPathValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeMethod
|
||||||
|
public void setup() throws URISyntaxException {
|
||||||
|
builder = new TestableDataFlowInfoPatchBuilder();
|
||||||
|
builder.urn(Urn.createFromString(TEST_URN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildDoesNotAffectPathValues() throws URISyntaxException {
|
||||||
|
String testName = "testFlow";
|
||||||
|
String testDescription = "Test description";
|
||||||
|
|
||||||
|
builder.setName(testName).setDescription(testDescription).addCustomProperty("key1", "value1");
|
||||||
|
|
||||||
|
// First call build()
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
// Then verify we can still access pathValues and they're correct
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 3);
|
||||||
|
|
||||||
|
// Verify the operations are still intact
|
||||||
|
assertEquals(pathValues.get(0).getLeft(), "add");
|
||||||
|
assertEquals(pathValues.get(0).getMiddle(), "/name");
|
||||||
|
assertEquals(pathValues.get(0).getRight().asText(), testName);
|
||||||
|
|
||||||
|
assertEquals(pathValues.get(1).getLeft(), "add");
|
||||||
|
assertEquals(pathValues.get(1).getMiddle(), "/description");
|
||||||
|
assertEquals(pathValues.get(1).getRight().asText(), testDescription);
|
||||||
|
|
||||||
|
assertEquals(pathValues.get(2).getLeft(), "add");
|
||||||
|
assertTrue(pathValues.get(2).getMiddle().startsWith("/customProperties/"));
|
||||||
|
assertEquals(pathValues.get(2).getRight().asText(), "value1");
|
||||||
|
|
||||||
|
// Verify we can call build() again without issues
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
// And verify pathValues are still accessible and correct
|
||||||
|
pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetName() {
|
||||||
|
String testName = "testFlow";
|
||||||
|
builder.setName(testName);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertEquals(operation.getMiddle(), "/name");
|
||||||
|
assertEquals(operation.getRight().asText(), testName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetDescription() {
|
||||||
|
String testDescription = "Test description";
|
||||||
|
builder.setDescription(testDescription);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertEquals(operation.getMiddle(), "/description");
|
||||||
|
assertEquals(operation.getRight().asText(), testDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetDescriptionNull() {
|
||||||
|
builder.setDescription(null);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "remove");
|
||||||
|
assertEquals(operation.getMiddle(), "/description");
|
||||||
|
assertNull(operation.getRight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetProject() {
|
||||||
|
String testProject = "testProject";
|
||||||
|
builder.setProject(testProject);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertEquals(operation.getMiddle(), "/project");
|
||||||
|
assertEquals(operation.getRight().asText(), testProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetProjectNull() {
|
||||||
|
builder.setProject(null);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "remove");
|
||||||
|
assertEquals(operation.getMiddle(), "/project");
|
||||||
|
assertNull(operation.getRight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetCreated() throws URISyntaxException {
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
String actor = "urn:li:corpuser:testUser";
|
||||||
|
TimeStamp created = new TimeStamp();
|
||||||
|
created.setTime(time);
|
||||||
|
created.setActor(Urn.createFromString(actor));
|
||||||
|
|
||||||
|
builder.setCreated(created);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertEquals(operation.getMiddle(), "/created");
|
||||||
|
JsonNode createdNode = operation.getRight();
|
||||||
|
assertTrue(createdNode.isObject());
|
||||||
|
assertEquals(createdNode.get("time").asLong(), time);
|
||||||
|
assertEquals(createdNode.get("actor").asText(), actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetCreatedNull() {
|
||||||
|
builder.setCreated(null);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "remove");
|
||||||
|
assertEquals(operation.getMiddle(), "/created");
|
||||||
|
assertNull(operation.getRight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetLastModified() throws URISyntaxException {
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
String actor = "urn:li:corpuser:testUser";
|
||||||
|
TimeStamp lastModified = new TimeStamp();
|
||||||
|
lastModified.setTime(time);
|
||||||
|
lastModified.setActor(Urn.createFromString(actor));
|
||||||
|
|
||||||
|
builder.setLastModified(lastModified);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertEquals(operation.getMiddle(), "/lastModified");
|
||||||
|
JsonNode lastModifiedNode = operation.getRight();
|
||||||
|
assertTrue(lastModifiedNode.isObject());
|
||||||
|
assertEquals(lastModifiedNode.get("time").asLong(), time);
|
||||||
|
assertEquals(lastModifiedNode.get("actor").asText(), actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetLastModifiedNull() {
|
||||||
|
builder.setLastModified(null);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "remove");
|
||||||
|
assertEquals(operation.getMiddle(), "/lastModified");
|
||||||
|
assertNull(operation.getRight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddCustomProperties() {
|
||||||
|
builder.addCustomProperty("key1", "value1").addCustomProperty("key2", "value2");
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 2);
|
||||||
|
|
||||||
|
pathValues.forEach(
|
||||||
|
operation -> {
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertTrue(operation.getMiddle().startsWith("/customProperties/"));
|
||||||
|
assertTrue(operation.getRight().isTextual());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveCustomProperty() {
|
||||||
|
builder.removeCustomProperty("key1");
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "remove");
|
||||||
|
assertEquals(operation.getMiddle(), "/customProperties/key1");
|
||||||
|
assertNull(operation.getRight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetCustomProperties() {
|
||||||
|
Map<String, String> properties = new HashMap<>();
|
||||||
|
properties.put("key1", "value1");
|
||||||
|
properties.put("key2", "value2");
|
||||||
|
|
||||||
|
builder.setCustomProperties(properties);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertEquals(operation.getMiddle(), "/customProperties");
|
||||||
|
assertTrue(operation.getRight().isObject());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,237 @@
|
|||||||
|
package com.linkedin.metadata.aspect.patch.builder;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
import static org.testng.Assert.assertNull;
|
||||||
|
import static org.testng.Assert.assertThrows;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.linkedin.common.Edge;
|
||||||
|
import com.linkedin.common.urn.DataJobUrn;
|
||||||
|
import com.linkedin.common.urn.DatasetUrn;
|
||||||
|
import com.linkedin.common.urn.Urn;
|
||||||
|
import com.linkedin.metadata.graph.LineageDirection;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.commons.lang3.tuple.ImmutableTriple;
|
||||||
|
import org.testng.annotations.BeforeMethod;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
public class DataJobInputOutputPatchBuilderTest {
|
||||||
|
|
||||||
|
private TestableDataJobInputOutputPatchBuilder builder;
|
||||||
|
private static final String TEST_DATAJOB_URN =
|
||||||
|
"urn:li:dataJob:(urn:li:dataFlow:(test,flow1,PROD),job1)";
|
||||||
|
private static final String TEST_DATASET_URN =
|
||||||
|
"urn:li:dataset:(urn:li:dataPlatform:hive,SampleTable,PROD)";
|
||||||
|
private static final String TEST_DATASET_FIELD_URN =
|
||||||
|
"urn:li:schemaField:(urn:li:dataset:(urn:li:dataPlatform:hive,SampleTable,PROD),id)";
|
||||||
|
|
||||||
|
// Test helper class to expose protected method
|
||||||
|
private static class TestableDataJobInputOutputPatchBuilder
|
||||||
|
extends DataJobInputOutputPatchBuilder {
|
||||||
|
public List<ImmutableTriple<String, String, JsonNode>> getTestPathValues() {
|
||||||
|
return getPathValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeMethod
|
||||||
|
public void setup() throws URISyntaxException {
|
||||||
|
builder = new TestableDataJobInputOutputPatchBuilder();
|
||||||
|
builder.urn(Urn.createFromString(TEST_DATAJOB_URN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildDoesNotAffectPathValues() throws URISyntaxException {
|
||||||
|
DataJobUrn dataJobUrn = DataJobUrn.createFromString(TEST_DATAJOB_URN);
|
||||||
|
DatasetUrn datasetUrn = DatasetUrn.createFromString(TEST_DATASET_URN);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.addInputDatajobEdge(dataJobUrn)
|
||||||
|
.addInputDatasetEdge(datasetUrn)
|
||||||
|
.addOutputDatasetEdge(datasetUrn);
|
||||||
|
|
||||||
|
// First call build()
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
// Then verify we can still access pathValues and they're correct
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 3);
|
||||||
|
|
||||||
|
// Verify we can call build() again without issues
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
// And verify pathValues are still accessible and correct
|
||||||
|
pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddInputDatajobEdge() throws URISyntaxException {
|
||||||
|
DataJobUrn dataJobUrn = DataJobUrn.createFromString(TEST_DATAJOB_URN);
|
||||||
|
builder.addInputDatajobEdge(dataJobUrn);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertTrue(operation.getMiddle().startsWith("/inputDatajobEdges/"));
|
||||||
|
assertTrue(operation.getRight().isObject());
|
||||||
|
assertEquals(operation.getRight().get("destinationUrn").asText(), dataJobUrn.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveInputDatajobEdge() throws URISyntaxException {
|
||||||
|
DataJobUrn dataJobUrn = DataJobUrn.createFromString(TEST_DATAJOB_URN);
|
||||||
|
builder.removeInputDatajobEdge(dataJobUrn);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "remove");
|
||||||
|
assertTrue(operation.getMiddle().startsWith("/inputDatajobEdges/"));
|
||||||
|
assertNull(operation.getRight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddInputDatasetEdge() throws URISyntaxException {
|
||||||
|
DatasetUrn datasetUrn = DatasetUrn.createFromString(TEST_DATASET_URN);
|
||||||
|
builder.addInputDatasetEdge(datasetUrn);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertTrue(operation.getMiddle().startsWith("/inputDatasetEdges/"));
|
||||||
|
assertTrue(operation.getRight().isObject());
|
||||||
|
assertEquals(operation.getRight().get("destinationUrn").asText(), datasetUrn.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveInputDatasetEdge() throws URISyntaxException {
|
||||||
|
DatasetUrn datasetUrn = DatasetUrn.createFromString(TEST_DATASET_URN);
|
||||||
|
builder.removeInputDatasetEdge(datasetUrn);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "remove");
|
||||||
|
assertTrue(operation.getMiddle().startsWith("/inputDatasetEdges/"));
|
||||||
|
assertNull(operation.getRight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddOutputDatasetEdge() throws URISyntaxException {
|
||||||
|
DatasetUrn datasetUrn = DatasetUrn.createFromString(TEST_DATASET_URN);
|
||||||
|
builder.addOutputDatasetEdge(datasetUrn);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertTrue(operation.getMiddle().startsWith("/outputDatasetEdges/"));
|
||||||
|
assertTrue(operation.getRight().isObject());
|
||||||
|
assertEquals(operation.getRight().get("destinationUrn").asText(), datasetUrn.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddInputDatasetField() throws URISyntaxException {
|
||||||
|
Urn fieldUrn = Urn.createFromString(TEST_DATASET_FIELD_URN);
|
||||||
|
builder.addInputDatasetField(fieldUrn);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertTrue(operation.getMiddle().startsWith("/inputDatasetFields/"));
|
||||||
|
assertTrue(operation.getRight().isTextual());
|
||||||
|
assertEquals(operation.getRight().asText(), fieldUrn.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveInputDatasetField() throws URISyntaxException {
|
||||||
|
Urn fieldUrn = Urn.createFromString(TEST_DATASET_FIELD_URN);
|
||||||
|
builder.removeInputDatasetField(fieldUrn);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "remove");
|
||||||
|
assertTrue(operation.getMiddle().startsWith("/inputDatasetFields/"));
|
||||||
|
assertNull(operation.getRight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddOutputDatasetField() throws URISyntaxException {
|
||||||
|
Urn fieldUrn = Urn.createFromString(TEST_DATASET_FIELD_URN);
|
||||||
|
builder.addOutputDatasetField(fieldUrn);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertTrue(operation.getMiddle().startsWith("/outputDatasetFields/"));
|
||||||
|
assertTrue(operation.getRight().isTextual());
|
||||||
|
assertEquals(operation.getRight().asText(), fieldUrn.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddEdgeWithDirection() throws URISyntaxException {
|
||||||
|
DatasetUrn datasetUrn = DatasetUrn.createFromString(TEST_DATASET_URN);
|
||||||
|
Edge edge = new Edge();
|
||||||
|
edge.setDestinationUrn(datasetUrn);
|
||||||
|
|
||||||
|
builder.addEdge(edge, LineageDirection.UPSTREAM);
|
||||||
|
builder.build();
|
||||||
|
|
||||||
|
List<ImmutableTriple<String, String, JsonNode>> pathValues = builder.getTestPathValues();
|
||||||
|
assertNotNull(pathValues);
|
||||||
|
assertEquals(pathValues.size(), 1);
|
||||||
|
|
||||||
|
ImmutableTriple<String, String, JsonNode> operation = pathValues.get(0);
|
||||||
|
assertEquals(operation.getLeft(), "add");
|
||||||
|
assertTrue(operation.getMiddle().startsWith("/inputDatasetEdges/"));
|
||||||
|
assertTrue(operation.getRight().isObject());
|
||||||
|
assertEquals(operation.getRight().get("destinationUrn").asText(), datasetUrn.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidEntityTypeThrowsException() throws URISyntaxException {
|
||||||
|
Urn invalidUrn = Urn.createFromString("urn:li:glossaryTerm:invalid");
|
||||||
|
Edge edge = new Edge();
|
||||||
|
edge.setDestinationUrn(invalidUrn);
|
||||||
|
|
||||||
|
assertThrows(
|
||||||
|
IllegalArgumentException.class,
|
||||||
|
() -> {
|
||||||
|
builder.addEdge(edge, LineageDirection.UPSTREAM);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user