GEN 1931 - Fix entity link accepted chars (#18391)

This commit is contained in:
Aniket Katkar 2024-10-29 15:29:23 +05:30
parent eb6a959886
commit 46cf15c12e
8 changed files with 300 additions and 210 deletions

View File

@ -236,7 +236,7 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
protected final boolean supportsEmptyDescription;
// Special characters supported in the entity name
protected String supportedNameCharacters = "_'-.&()" + RANDOM_STRING_GENERATOR.generate(1);
protected String supportedNameCharacters = "_'-.&()[]" + RANDOM_STRING_GENERATOR.generate(1);
protected final boolean supportsCustomExtension;
@ -250,7 +250,7 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
public static final String DATA_CONSUMER_ROLE_NAME = "DataConsumer";
public static final String ENTITY_LINK_MATCH_ERROR =
"[entityLink must match \"(?U)^<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#%]+>$\"]";
"[entityLink must match \"(?U)^<#E::\\w+::(?:[^:<>|]|:[^:<>|])+(?:::(?:[^:<>|]|:[^:<>|])+)*>$\"]";
// Random unicode string generator to test entity name accepts all the unicode characters
protected static final RandomStringGenerator RANDOM_STRING_GENERATOR =

View File

@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.openmetadata.common.utils.CommonUtil.listOf;
import static org.openmetadata.schema.type.ColumnDataType.BIGINT;
@ -2572,152 +2573,53 @@ public class TestCaseResourceTest extends EntityResourceTest<TestCase, CreateTes
}
@Test
void resolved_test_case_deletes_sample_data(TestInfo test) throws IOException, ParseException {
CreateTestCase create =
createRequest(test)
.withEntityLink(TABLE_LINK)
void test_testCaseInvalidEntityLinkTest(TestInfo testInfo) throws IOException {
// Invalid entity link as not parsable by antlr parser
String entityLink = "<#E::table::special!@#$%^&*()_+[]{}|;:\\'\",./?>";
CreateTestCase create = createRequest(testInfo);
create
.withEntityLink(entityLink)
.withTestSuite(TEST_SUITE1.getFullyQualifiedName())
.withTestDefinition(TEST_DEFINITION3.getFullyQualifiedName())
.withParameterValues(
List.of(
new TestCaseParameterValue().withValue("100").withName("missingCountValue")));
TestCase testCase = createAndCheckEntity(create, ADMIN_AUTH_HEADERS);
List<String> columns = Arrays.asList(C1, C2, C3);
List.of(new TestCaseParameterValue().withValue("100").withName("missingCountValue")));
// Add 3 rows of sample data for 3 columns
List<List<Object>> rows =
Arrays.asList(
Arrays.asList("c1Value1", 1, true),
Arrays.asList("c1Value2", null, false),
Arrays.asList("c1Value3", 3, true));
assertThrows(
HttpResponseException.class,
() -> createAndCheckEntity(create, ADMIN_AUTH_HEADERS),
"entityLink must match \"(?U)^<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#%]+>$\"");
putTestCaseResult(
testCase.getFullyQualifiedName(),
new TestCaseResult()
.withResult("result")
.withTestCaseStatus(TestCaseStatus.Failed)
.withTimestamp(TestUtils.dateToTimestamp("2024-01-01")),
ADMIN_AUTH_HEADERS);
entityLink = "<#E::table::user<name>::column>";
create.setEntityLink(entityLink);
assertThrows(
HttpResponseException.class,
() -> createAndCheckEntity(create, ADMIN_AUTH_HEADERS),
"entityLink must match \"(?U)^<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#%]+>$\"");
putFailedRowsSample(testCase, columns, rows, ADMIN_AUTH_HEADERS);
entityLink = "<#E::table::user>name::column>";
create.setEntityLink(entityLink);
assertThrows(
HttpResponseException.class,
() -> createAndCheckEntity(create, ADMIN_AUTH_HEADERS),
"entityLink must match \"(?U)^<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#%]+>$\"");
// resolving test case deletes the sample data
TestCaseResult testCaseResult =
new TestCaseResult()
.withResult("tested")
.withTestCaseStatus(TestCaseStatus.Success)
.withTimestamp(TestUtils.dateToTimestamp("2021-09-09"));
putTestCaseResult(testCase.getFullyQualifiedName(), testCaseResult, ADMIN_AUTH_HEADERS);
assertResponse(
() -> getSampleData(testCase.getId(), ADMIN_AUTH_HEADERS),
NOT_FOUND,
FAILED_ROWS_SAMPLE_EXTENSION + " instance for " + testCase.getId() + " not found");
entityLink = "<#E::table::foo<>bar::baz>\");";
create.setEntityLink(entityLink);
assertThrows(
HttpResponseException.class,
() -> createAndCheckEntity(create, ADMIN_AUTH_HEADERS),
"entityLink must match \"(?U)^<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#%]+>$\"");
entityLink = "<#E::table::::baz>";
create.setEntityLink(entityLink);
assertThrows(
HttpResponseException.class,
() -> createAndCheckEntity(create, ADMIN_AUTH_HEADERS),
"entityLink must match \"(?U)^<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#%]+>$\"");
}
@Test
void test_sensitivePIISampleData(TestInfo test) throws IOException, ParseException {
// Create table with owner and a column tagged with PII.Sensitive
TableResourceTest tableResourceTest = new TableResourceTest();
CreateTable tableReq = getSensitiveTableReq(test, tableResourceTest);
Table sensitiveTable = tableResourceTest.createAndCheckEntity(tableReq, ADMIN_AUTH_HEADERS);
String sensitiveColumnLink =
String.format("<#E::table::%s::columns::%s>", sensitiveTable.getFullyQualifiedName(), C1);
CreateTestCase create =
createRequest(test)
.withEntityLink(sensitiveColumnLink)
.withTestSuite(TEST_SUITE1.getFullyQualifiedName())
.withTestDefinition(TEST_DEFINITION3.getFullyQualifiedName())
.withParameterValues(
List.of(
new TestCaseParameterValue().withValue("100").withName("missingCountValue")));
TestCase testCase = createAndCheckEntity(create, ADMIN_AUTH_HEADERS);
putTestCaseResult(
testCase.getFullyQualifiedName(),
new TestCaseResult()
.withResult("result")
.withTestCaseStatus(TestCaseStatus.Failed)
.withTimestamp(TestUtils.dateToTimestamp("2024-01-01")),
ADMIN_AUTH_HEADERS);
List<String> columns = List.of(C1);
// Add 3 rows of sample data
List<List<Object>> rows =
Arrays.asList(List.of("c1Value1"), List.of("c1Value2"), List.of("c1Value3"));
// add sample data
putFailedRowsSample(testCase, columns, rows, ADMIN_AUTH_HEADERS);
// assert values are not masked for the table owner
TableData data = getSampleData(testCase.getId(), authHeaders(USER1.getName()));
assertFalse(
data.getRows().stream()
.flatMap(List::stream)
.map(r -> r == null ? "" : r)
.map(Object::toString)
.anyMatch(MASKED_VALUE::equals));
// assert values are masked when is not the table owner
data = getSampleData(testCase.getId(), authHeaders(USER2.getName()));
assertEquals(
3,
data.getRows().stream()
.flatMap(List::stream)
.map(r -> r == null ? "" : r)
.map(Object::toString)
.filter(MASKED_VALUE::equals)
.count());
}
@Test
void test_addInspectionQuery(TestInfo test) throws IOException {
CreateTestCase create =
createRequest(test)
.withEntityLink(TABLE_LINK)
.withTestSuite(TEST_SUITE1.getFullyQualifiedName())
.withTestDefinition(TEST_DEFINITION3.getFullyQualifiedName())
.withParameterValues(
List.of(
new TestCaseParameterValue().withValue("100").withName("missingCountValue")));
TestCase testCase = createAndCheckEntity(create, ADMIN_AUTH_HEADERS);
String inspectionQuery = "SELECT * FROM test_table WHERE column1 = 'value1'";
putInspectionQuery(testCase, inspectionQuery, ADMIN_AUTH_HEADERS);
TestCase updated = getTestCase(testCase.getFullyQualifiedName(), ADMIN_AUTH_HEADERS);
assertEquals(updated.getInspectionQuery(), inspectionQuery);
}
@Test
@Execution(ExecutionMode.CONCURRENT)
protected void post_entityCreateWithInvalidName_400() {
// Create an entity with mandatory name field null
final CreateTestCase request = createRequest(null, "description", "displayName", null);
assertResponseContains(
() -> createEntity(request, ADMIN_AUTH_HEADERS), BAD_REQUEST, "[name must not be null]");
// Create an entity with mandatory name field empty
final CreateTestCase request1 = createRequest("", "description", "displayName", null);
assertResponseContains(
() -> createEntity(request1, ADMIN_AUTH_HEADERS),
BAD_REQUEST,
TestUtils.getEntityNameLengthError(entityClass));
// Any entity name that has EntityLink separator must fail
final CreateTestCase request3 =
createRequest("invalid::Name", "description", "displayName", null);
assertResponseContains(
() -> createEntity(request3, ADMIN_AUTH_HEADERS), BAD_REQUEST, "name must match");
}
@Test
void createUpdate_DynamicAssertionTests(TestInfo testInfo) throws IOException {
CreateTestCase create = createRequest(testInfo).withUseDynamicAssertion(true);
TestCase testCase = createAndCheckEntity(create, ADMIN_AUTH_HEADERS);
testCase = getTestCase(testCase.getFullyQualifiedName(), ADMIN_AUTH_HEADERS);
assertTrue(testCase.getUseDynamicAssertion());
CreateTestCase update = create.withUseDynamicAssertion(false);
updateEntity(update, OK, ADMIN_AUTH_HEADERS);
testCase = getTestCase(testCase.getFullyQualifiedName(), ADMIN_AUTH_HEADERS);
assertFalse(testCase.getUseDynamicAssertion());
}
private void putInspectionQuery(TestCase testCase, String sql, Map<String, String> authHeaders)
throws IOException {
TestCase putResponse = putInspectionQuery(testCase.getId(), sql, authHeaders);
private void putInspectionQuery(TestCase testCase, String sql) throws IOException {
TestCase putResponse = putInspectionQuery(testCase.getId(), sql, ADMIN_AUTH_HEADERS);
assertEquals(sql, putResponse.getInspectionQuery());
}

View File

@ -98,8 +98,9 @@ public class EventSubscriptionResourceTest
@Test
void post_alertActionWithEnabledStateChange(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String endpoint = test.getDisplayName();
LOG.info("creating webhook in disabled state");
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/webhook/" + webhookName;
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/webhook/" + endpoint;
// Create a Disabled Generic Webhook
CreateEventSubscription genericWebhookActionRequest =
createRequest(webhookName).withEnabled(false).withDestinations(getWebhook(uri));
@ -108,7 +109,7 @@ public class EventSubscriptionResourceTest
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(DISABLED, status.getStatus());
WebhookCallbackResource.EventDetails details =
webhookCallbackResource.getEventDetails(webhookName);
webhookCallbackResource.getEventDetails(endpoint);
assertNull(details);
//
// Now enable the webhook
@ -143,7 +144,7 @@ public class EventSubscriptionResourceTest
assertEquals(SubscriptionStatus.Status.ACTIVE, status2.getStatus());
// Ensure the call back notification has started
details = waitForFirstEvent(alert.getId(), webhookName, 25);
details = waitForFirstEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
SubscriptionStatus successDetails =
getStatus(alert.getId(), Response.Status.OK.getStatusCode());
@ -454,7 +455,8 @@ public class EventSubscriptionResourceTest
@Test
public void post_createAndValidateEventSubscription(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/webhook/" + webhookName;
String endpoint = test.getDisplayName();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/webhook/" + endpoint;
CreateEventSubscription enabledWebhookRequest =
new CreateEventSubscription()
@ -491,7 +493,8 @@ public class EventSubscriptionResourceTest
@Test
public void post_duplicateAlertsAreNotAllowed(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/webhook/" + webhookName;
String endpoint = test.getDisplayName();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/webhook/" + endpoint;
CreateEventSubscription genericWebhookRequest =
new CreateEventSubscription()
@ -599,7 +602,8 @@ public class EventSubscriptionResourceTest
@Test
public void post_createAndValidateEventSubscription_SLACK(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String endpoint = test.getDisplayName();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
CreateEventSubscription enabledWebhookRequest =
new CreateEventSubscription()
@ -614,7 +618,7 @@ public class EventSubscriptionResourceTest
EventSubscription alert = createEntity(enabledWebhookRequest, ADMIN_AUTH_HEADERS);
waitForAllEventToComplete(alert.getId());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
ConcurrentLinkedQueue<SlackMessage> events = details.getEvents();
for (SlackMessage event : events) {
validateSlackMessage(alert, event);
@ -675,8 +679,9 @@ public class EventSubscriptionResourceTest
@Test
void post_tableResource_filterByOwner_alertAction(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String endpoint = test.getDisplayName();
TableResourceTest tableResourceTest = new TableResourceTest();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
// Create the event subscription request with the Slack destination and table as the resource
CreateEventSubscription genericWebhookActionRequest =
@ -700,7 +705,7 @@ public class EventSubscriptionResourceTest
assertEquals(ACTIVE, status.getStatus());
// Verify no Slack events triggered initially
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
assertNull(details);
// Create a table with a different owner (USER2), expect no alert
@ -709,14 +714,14 @@ public class EventSubscriptionResourceTest
.createRequest(test.getClass().getName() + generateUniqueNumberAsString())
.withOwners(List.of(USER2.getEntityReference()));
tableResourceTest.createEntity(createTable1, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertNull(details);
// Create another table with the owner that matches the filter (USER_TEAM21), expect an alert
CreateTable createTable =
tableResourceTest.createRequest(test).withOwners(List.of(USER_TEAM21.getEntityReference()));
Table table = tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
// Clean up: delete the event subscription and created tables
@ -728,7 +733,8 @@ public class EventSubscriptionResourceTest
void post_tableResource_filterByDomain_alertAction(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
TableResourceTest tableResourceTest = new TableResourceTest();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String endpoint = test.getDisplayName();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
// Create the event subscription request with the Slack destination and table resource with
// filterByDomain
@ -754,7 +760,7 @@ public class EventSubscriptionResourceTest
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(ACTIVE, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
assertNull(details);
CreateDomain createDomain2 = domainResourceTest.createRequest("Engineering_2");
@ -762,7 +768,7 @@ public class EventSubscriptionResourceTest
CreateTable createTable =
tableResourceTest.createRequest(test).withDomain(domainSecond.getName());
tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
// changeEvent on the table with correct domain will result in alerts
assertNull(details);
@ -771,7 +777,7 @@ public class EventSubscriptionResourceTest
.createRequest(test.getClass().getName() + "_secondTable")
.withDomain(domain.getName());
tableResourceTest.createEntity(createTable2, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
}
@ -779,7 +785,8 @@ public class EventSubscriptionResourceTest
void post_tableResource_fqnFilter_alertAction(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
TableResourceTest tableResourceTest = new TableResourceTest();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String endpoint = test.getDisplayName();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
// Create the event subscription request with slack destination and table as the resource with
// filterByFqn
@ -798,20 +805,20 @@ public class EventSubscriptionResourceTest
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(ACTIVE, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
// alerts will trigger on the changeEvent of table resource
assertNull(details);
CreateTable createTable =
tableResourceTest.createRequest(test.getClass().getName() + generateUniqueNumberAsString());
Table table1 = tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
// alerts will trigger on the changeEvent of table resource with correct fqn
assertNull(details);
CreateTable createTable2 = tableResourceTest.createRequest(test).withName("test");
Table table2 = tableResourceTest.createEntity(createTable2, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
tableResourceTest.deleteEntity(table1.getId(), ADMIN_AUTH_HEADERS);
@ -821,7 +828,8 @@ public class EventSubscriptionResourceTest
@Test
void post_excluded_filters_alertAction(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String endpoint = test.getDisplayName();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
// Create the event subscription request with the Slack destination and table resource
CreateEventSubscription genericWebhookActionRequest =
@ -841,7 +849,7 @@ public class EventSubscriptionResourceTest
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(ACTIVE, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
assertNull(details);
TableResourceTest tableResourceTest = new TableResourceTest();
@ -851,7 +859,7 @@ public class EventSubscriptionResourceTest
tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS);
// Wait for the slack event and verify its details
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
// filters are EXCLUDED
assertNull(details);
@ -862,7 +870,8 @@ public class EventSubscriptionResourceTest
void post_tableResource_filterByOwner_AND_filterByDomain_Filter_alertAction(TestInfo test)
throws IOException {
String webhookName = getEntityName(test);
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String endpoint = test.getDisplayName();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
// Create the event subscription request with the Slack destination and table resource with
// filterByOwner AND filterByDomain
@ -894,7 +903,7 @@ public class EventSubscriptionResourceTest
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(ACTIVE, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
assertNull(details);
// wrong owner and correct domain -> no alerts
@ -906,7 +915,7 @@ public class EventSubscriptionResourceTest
.withOwners(List.of(USER1.getEntityReference()))
.withDomain(domain.getName());
tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertNull(details);
// correct owner and wrong domain -> no alerts
@ -920,7 +929,7 @@ public class EventSubscriptionResourceTest
.withOwners(List.of(USER1.getEntityReference()))
.withDomain(domain2.getName());
tableResourceTest.createEntity(createTable2, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertNull(details);
// correcr owner and correct domain -> alerts
@ -933,7 +942,7 @@ public class EventSubscriptionResourceTest
Table table = tableResourceTest.createEntity(createTable3, ADMIN_AUTH_HEADERS);
// Wait for the slack event and verify its details
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
tableResourceTest.deleteEntity(table.getId(), ADMIN_AUTH_HEADERS);
}
@ -942,7 +951,8 @@ public class EventSubscriptionResourceTest
void post_tableResource_noFilters_alertAction(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
TableResourceTest tableResourceTest = new TableResourceTest();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String endpoint = test.getDisplayName();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
// Create the event subscription request with the Slack destination and table as the resource
// without any filters
@ -955,7 +965,7 @@ public class EventSubscriptionResourceTest
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(ACTIVE, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
// alerts will trigger on the changeEvent of table resource
assertNull(details);
@ -964,14 +974,15 @@ public class EventSubscriptionResourceTest
tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS);
// Wait for the slack event and verify its details
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
}
@Test
void post_topicResource_noFilters_alertAction(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String endpoint = test.getDisplayName();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
CreateEventSubscription genericWebhookActionRequest =
createRequest(webhookName)
@ -981,7 +992,7 @@ public class EventSubscriptionResourceTest
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(ACTIVE, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
// Alerts are triggered only by ChangeEvent occurrences related to resources as topic
assertNull(details);
@ -993,15 +1004,16 @@ public class EventSubscriptionResourceTest
.withMessageSchema(TopicResourceTest.SCHEMA.withSchemaFields(TopicResourceTest.fields));
topicResourceTest.createEntity(topicRequest, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
}
@Test
void post_topicResource_filterByFqn_alertAction(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String endpoint = test.getDisplayName();
TopicResourceTest topicResourceTest = new TopicResourceTest();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
CreateEventSubscription genericWebhookActionRequest =
createRequest(webhookName)
@ -1020,7 +1032,7 @@ public class EventSubscriptionResourceTest
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(ACTIVE, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
// Alerts are triggered only by changeEvent occurrences related to resources as topic with
// filterByFqn
@ -1031,7 +1043,7 @@ public class EventSubscriptionResourceTest
.createRequest(test)
.withMessageSchema(TopicResourceTest.SCHEMA.withSchemaFields(TopicResourceTest.fields));
topicResourceTest.createEntity(topicRequest, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
// changeEvents associated with correct fqn will result in alerts
assertNull(details);
@ -1041,15 +1053,16 @@ public class EventSubscriptionResourceTest
.withMessageSchema(TopicResourceTest.SCHEMA.withSchemaFields(TopicResourceTest.fields));
topicResourceTest.createEntity(topicRequest2, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
}
@Test
void post_topicResource_domain_alertAction(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String endpoint = test.getDisplayName();
TopicResourceTest topicResourceTest = new TopicResourceTest();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
CreateEventSubscription genericWebhookActionRequest =
createRequest(webhookName)
@ -1072,7 +1085,7 @@ public class EventSubscriptionResourceTest
EventSubscription alert = createAndCheckEntity(genericWebhookActionRequest, ADMIN_AUTH_HEADERS);
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(ACTIVE, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
// Alerts are triggered only by ChangeEvent occurrences related to resources as topic by
// filterByDomain
@ -1085,15 +1098,16 @@ public class EventSubscriptionResourceTest
.withMessageSchema(TopicResourceTest.SCHEMA.withSchemaFields(TopicResourceTest.fields));
topicResourceTest.createEntity(topicRequest, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
}
@Test
void post_topicResource_owner_alertAction(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String endpoint = test.getDisplayName();
TopicResourceTest topicResourceTest = new TopicResourceTest();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
CreateEventSubscription genericWebhookActionRequest =
createRequest(webhookName)
@ -1110,7 +1124,7 @@ public class EventSubscriptionResourceTest
EventSubscription alert = createAndCheckEntity(genericWebhookActionRequest, ADMIN_AUTH_HEADERS);
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(ACTIVE, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
// Alerts are triggered only by changeEvent occurrences related to resources as topic by
// filerByOwner
@ -1123,7 +1137,7 @@ public class EventSubscriptionResourceTest
.withMessageSchema(TopicResourceTest.SCHEMA.withSchemaFields(TopicResourceTest.fields));
topicResourceTest.createEntity(topicRequest, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
}
@ -1131,8 +1145,9 @@ public class EventSubscriptionResourceTest
void post_topicResource_owner_AND_domain_alertAction(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
DomainResourceTest domainResourceTest = new DomainResourceTest();
String endpoint = test.getDisplayName();
TopicResourceTest topicResourceTest = new TopicResourceTest();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
CreateEventSubscription genericWebhookActionRequest =
createRequest(webhookName)
@ -1160,7 +1175,7 @@ public class EventSubscriptionResourceTest
EventSubscription alert = createAndCheckEntity(genericWebhookActionRequest, ADMIN_AUTH_HEADERS);
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(ACTIVE, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
// Alerts are triggered only by ChangeEvent occurrences related to resources as topic by
// filterByDomain
@ -1175,7 +1190,7 @@ public class EventSubscriptionResourceTest
.withDomain(domain.getName())
.withMessageSchema(TopicResourceTest.SCHEMA.withSchemaFields(TopicResourceTest.fields));
topicResourceTest.createEntity(topicRequest, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertNull(details);
// correct owner AND wrong domain -> no alerts
@ -1190,7 +1205,7 @@ public class EventSubscriptionResourceTest
.withDomain(domain2.getName())
.withMessageSchema(TopicResourceTest.SCHEMA.withSchemaFields(TopicResourceTest.fields));
topicResourceTest.createEntity(topicRequest2, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertNull(details);
// correct owner AND correct domain -> alerts
@ -1202,14 +1217,15 @@ public class EventSubscriptionResourceTest
.withMessageSchema(TopicResourceTest.SCHEMA.withSchemaFields(TopicResourceTest.fields));
topicResourceTest.createEntity(topicRequest3, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
}
@Test
void post_ingestionPiplelineResource_noFilter_alertAction(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String endpoint = test.getDisplayName();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
CreateEventSubscription genericWebhookActionRequest =
createRequest(webhookName)
@ -1220,7 +1236,7 @@ public class EventSubscriptionResourceTest
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(ACTIVE, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
// Alerts are triggered only by ChangeEvent occurrences related to resources as
// ingestionPipeline by domain filter
@ -1244,15 +1260,16 @@ public class EventSubscriptionResourceTest
ingestionPipelineResourceTest.createEntity(request, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
}
@Test
void post_ingestionPiplelineResource_owner_alertAction(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String endpoint = test.getDisplayName();
LOG.info("creating webhook in disabled state");
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
CreateEventSubscription genericWebhookActionRequest =
createRequest(webhookName)
@ -1272,7 +1289,7 @@ public class EventSubscriptionResourceTest
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(ACTIVE, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
// Alerts are triggered only by ChangeEvent occurrences related to resources as
// ingestionPipeline
@ -1296,7 +1313,7 @@ public class EventSubscriptionResourceTest
ingestionPipelineResourceTest.createEntity(request, ADMIN_AUTH_HEADERS);
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
}
@ -1307,8 +1324,9 @@ public class EventSubscriptionResourceTest
@Test
void post_alertActionWithEnabledStateChange_SLACK(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String endpoint = test.getDisplayName();
LOG.info("creating webhook in disabled state");
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + webhookName;
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/slack/" + endpoint;
// Create a Disabled Generic Webhook
CreateEventSubscription genericWebhookActionRequest =
@ -1318,7 +1336,7 @@ public class EventSubscriptionResourceTest
// For the DISABLED Publisher are not available, so it will have no status
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(DISABLED, status.getStatus());
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(webhookName);
SlackCallbackResource.EventDetails details = slackCallbackResource.getEventDetails(endpoint);
assertNull(details);
LOG.info("Enabling webhook Action");
@ -1339,7 +1357,7 @@ public class EventSubscriptionResourceTest
assertEquals(SubscriptionStatus.Status.ACTIVE, status2.getStatus());
// Ensure the call back notification has started
details = waitForFirstSlackEvent(alert.getId(), webhookName, 25);
details = waitForFirstSlackEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
ConcurrentLinkedQueue<SlackMessage> messages = details.getEvents();
for (SlackMessage sm : messages) {
@ -1451,7 +1469,8 @@ public class EventSubscriptionResourceTest
@Test
public void post_createAndValidateEventSubscription_MSTEAMS(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/msteams/" + webhookName;
String endpoint = test.getDisplayName();
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/msteams/" + endpoint;
CreateEventSubscription enabledWebhookRequest =
new CreateEventSubscription()
@ -1466,8 +1485,7 @@ public class EventSubscriptionResourceTest
EventSubscription alert = createEntity(enabledWebhookRequest, ADMIN_AUTH_HEADERS);
waitForAllEventToComplete(alert.getId());
MSTeamsCallbackResource.EventDetails details =
teamsCallbackResource.getEventDetails(webhookName);
MSTeamsCallbackResource.EventDetails details = teamsCallbackResource.getEventDetails(endpoint);
Awaitility.await()
.pollInterval(Duration.ofMillis(100L))
@ -1495,8 +1513,9 @@ public class EventSubscriptionResourceTest
@Test
void post_alertActionWithEnabledStateChange_MSTeams(TestInfo test) throws IOException {
String webhookName = getEntityName(test);
String endpoint = test.getDisplayName();
LOG.info("creating webhook in disabled state");
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/msteams/" + webhookName;
String uri = "http://localhost:" + APP.getLocalPort() + "/api/v1/test/msteams/" + endpoint;
// Create a Disabled Generic Webhook
CreateEventSubscription genericWebhookActionRequest =
@ -1506,8 +1525,7 @@ public class EventSubscriptionResourceTest
// For the DISABLED Publisher are not available, so it will have no status
SubscriptionStatus status = getStatus(alert.getId(), Response.Status.OK.getStatusCode());
assertEquals(DISABLED, status.getStatus());
MSTeamsCallbackResource.EventDetails details =
teamsCallbackResource.getEventDetails(webhookName);
MSTeamsCallbackResource.EventDetails details = teamsCallbackResource.getEventDetails(endpoint);
assertNull(details);
LOG.info("Enabling webhook Action");
@ -1528,7 +1546,7 @@ public class EventSubscriptionResourceTest
assertEquals(SubscriptionStatus.Status.ACTIVE, status2.getStatus());
// Ensure the call back notification has started
details = waitForFirstMSTeamsEvent(alert.getId(), webhookName, 25);
details = waitForFirstMSTeamsEvent(alert.getId(), endpoint, 25);
assertEquals(1, details.getEvents().size());
ConcurrentLinkedQueue<TeamsMessage> messages = details.getEvents();
for (TeamsMessage teamsMessage : messages) {

View File

@ -219,7 +219,8 @@ public class FeedResourceTest extends OpenMetadataApplicationTest {
// Create thread without addressed to entity in the request
CreateThread create = create().withFrom(USER.getName()).withAbout("<>"); // Invalid EntityLink
String failureReason = "[about must match \"(?U)^<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#%]+>$\"]";
String failureReason =
"[about must match \"(?U)^<#E::\\w+::(?:[^:<>|]|:[^:<>|])+(?:::(?:[^:<>|]|:[^:<>|])+)*>$\"]";
assertResponseContains(
() -> createThread(create, USER_AUTH_HEADERS), BAD_REQUEST, failureReason);

View File

@ -153,7 +153,7 @@ public class SuggestionsResourceTest extends OpenMetadataApplicationTest {
CreateSuggestion create = create().withEntityLink("<>"); // Invalid EntityLink
String failureReason =
"[entityLink must match \"(?U)^<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#%]+>$\"]";
"[entityLink must match \"(?U)^<#E::\\w+::(?:[^:<>|]|:[^:<>|])+(?:::(?:[^:<>|]|:[^:<>|])+)*>$\"]";
assertResponseContains(
() -> createSuggestion(create, USER_AUTH_HEADERS), BAD_REQUEST, failureReason);

View File

@ -2,9 +2,12 @@ package org.openmetadata.service.util;
import static org.junit.jupiter.api.Assertions.*;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.openmetadata.schema.entity.data.GlossaryTerm;
import org.openmetadata.schema.entity.data.Table;
import org.openmetadata.service.resources.feeds.MessageParser;
class EntityUtilTest {
@Test
@ -15,4 +18,167 @@ class EntityUtilTest {
EntityUtil.isDescriptionRequired(
GlossaryTerm.class)); // GlossaryTerm entity requires description
}
@Test
void test_entityLinkParser() {
// Valid entity links
Map<String, String> expected = new HashMap<>();
expected.put("entityLink", "<#E::table::users>");
expected.put("arrayFieldName", null);
expected.put("arrayFieldValue", null);
expected.put("fieldName", null);
expected.put("entityFQN", "users");
expected.put("entityType", "table");
expected.put("linkType", "ENTITY");
expected.put("fullyQualifiedFieldType", "table");
expected.put("fullyQualifiedFieldValue", "users");
verifyEntityLinkParser(expected);
expected.clear();
expected.put("entityLink", "<#E::table::users.foo.\"bar.baz\">");
expected.put("arrayFieldName", null);
expected.put("arrayFieldValue", null);
expected.put("fieldName", null);
expected.put("entityFQN", "users.foo.\"bar.baz\"");
expected.put("entityType", "table");
expected.put("linkType", "ENTITY");
expected.put("fullyQualifiedFieldType", "table");
expected.put("fullyQualifiedFieldValue", "users.foo.\"bar.baz\"");
verifyEntityLinkParser(expected);
expected.clear();
expected.put("entityLink", "<#E::db::customers>");
expected.put("arrayFieldName", null);
expected.put("arrayFieldValue", null);
expected.put("fieldName", null);
expected.put("entityFQN", "customers");
expected.put("entityType", "db");
expected.put("linkType", "ENTITY");
expected.put("fullyQualifiedFieldType", "db");
expected.put("fullyQualifiedFieldValue", "customers");
verifyEntityLinkParser(expected);
expected.clear();
expected.put("entityLink", "<#E::table::users::column::id>");
expected.put("arrayFieldName", "id");
expected.put("arrayFieldValue", null);
expected.put("fieldName", "column");
expected.put("entityFQN", "users");
expected.put("entityType", "table");
expected.put("linkType", "ENTITY_ARRAY_FIELD");
expected.put("fullyQualifiedFieldType", "table.column.member");
expected.put("fullyQualifiedFieldValue", "users.id");
verifyEntityLinkParser(expected);
expected.clear();
expected.put("entityLink", "<#E::table::orders::column::status::type::enum>");
expected.put("arrayFieldName", "status");
expected.put("arrayFieldValue", "type::enum");
expected.put("fieldName", "column");
expected.put("entityFQN", "orders");
expected.put("entityType", "table");
expected.put("linkType", "ENTITY_ARRAY_FIELD");
expected.put("fullyQualifiedFieldType", "table.column.member");
expected.put("fullyQualifiedFieldValue", "orders.status.type::enum");
verifyEntityLinkParser(expected);
expected.clear();
expected.put("entityLink", "<#E::db::schema::table::view::column>");
expected.put("arrayFieldName", "view");
expected.put("arrayFieldValue", "column");
expected.put("fieldName", "table");
expected.put("entityFQN", "schema");
expected.put("entityType", "db");
expected.put("linkType", "ENTITY_ARRAY_FIELD");
expected.put("fullyQualifiedFieldType", "db.table.member");
expected.put("fullyQualifiedFieldValue", "schema.view.column");
verifyEntityLinkParser(expected);
expected.clear();
expected.put("entityLink", "<#E::table::foo@bar>");
expected.put("arrayFieldName", null);
expected.put("arrayFieldValue", null);
expected.put("fieldName", null);
expected.put("entityFQN", "foo@bar");
expected.put("entityType", "table");
expected.put("linkType", "ENTITY");
expected.put("fullyQualifiedFieldType", "table");
expected.put("fullyQualifiedFieldValue", "foo@bar");
verifyEntityLinkParser(expected);
expected.clear();
expected.put("entityLink", "<#E::table::foo[bar]>");
expected.put("arrayFieldName", null);
expected.put("arrayFieldValue", null);
expected.put("fieldName", null);
expected.put("entityFQN", "foo[bar]");
expected.put("entityType", "table");
expected.put("linkType", "ENTITY");
expected.put("fullyQualifiedFieldType", "table");
expected.put("fullyQualifiedFieldValue", "foo[bar]");
verifyEntityLinkParser(expected);
expected.clear();
expected.put("entityLink", "<#E::table::special!@#$%^&*()_+[]{};:\\'\",./?>");
expected.put("arrayFieldName", null);
expected.put("arrayFieldValue", null);
expected.put("fieldName", null);
expected.put("entityFQN", "special!@#$%^&*()_+[]{};:\\'\",./?");
expected.put("entityType", "table");
expected.put("linkType", "ENTITY");
expected.put("fullyQualifiedFieldType", "table");
expected.put("fullyQualifiedFieldValue", "special!@#$%^&*()_+[]{};:\\'\",./?");
verifyEntityLinkParser(expected);
// Invalid entity link
expected.clear();
expected.put("entityLink", "<#E::table::special!@#$%^&*()_+[]{}|;:\\'\",./?>");
// EntityLink with `|` character will not be parsed correctly and everything after `|` will be
// ignored
org.opentest4j.AssertionFailedError exception =
assertThrows(
org.opentest4j.AssertionFailedError.class, () -> verifyEntityLinkParser(expected));
assertEquals(
"expected: <<#E::table::special!@#$%^&*()_+[]{}|;:\\'\",./?>> but was: <<#E::table::special!@#$%^&*()_+[]{}>>",
exception.getMessage());
expected.clear();
expected.put("entityLink", "<#E::table::user<name>::column>");
IllegalArgumentException argException =
assertThrows(IllegalArgumentException.class, () -> verifyEntityLinkParser(expected));
assertEquals(
"Entity link was not found in <#E::table::user<name>::column>", argException.getMessage());
expected.clear();
expected.put("entityLink", "<#E::table::user>name::column>");
exception =
assertThrows(
org.opentest4j.AssertionFailedError.class, () -> verifyEntityLinkParser(expected));
assertEquals(
"expected: <<#E::table::user>name::column>> but was: <<#E::table::user>>",
exception.getMessage());
expected.clear();
expected.put("entityLink", "<#E::table::foo<>bar::baz>");
argException =
assertThrows(IllegalArgumentException.class, () -> verifyEntityLinkParser(expected));
assertEquals(
"Entity link was not found in <#E::table::foo<>bar::baz>", argException.getMessage());
}
void verifyEntityLinkParser(Map<String, String> expected) {
MessageParser.EntityLink entityLink =
MessageParser.EntityLink.parse(expected.get("entityLink"));
assertEquals(expected.get("entityLink"), entityLink.getLinkString());
assertEquals(expected.get("arrayFieldName"), entityLink.getArrayFieldName());
assertEquals(expected.get("arrayFieldValue"), entityLink.getArrayFieldValue());
assertEquals(expected.get("entityType"), entityLink.getEntityType());
assertEquals(expected.get("fieldName"), entityLink.getFieldName());
assertEquals(expected.get("entityFQN"), entityLink.getEntityFQN());
assertEquals(expected.get("linkType"), entityLink.getLinkType().toString());
assertEquals(expected.get("fullyQualifiedFieldType"), entityLink.getFullyQualifiedFieldType());
assertEquals(
expected.get("fullyQualifiedFieldValue"), entityLink.getFullyQualifiedFieldValue());
}
}

View File

@ -113,7 +113,7 @@
"entityLink": {
"description": "Link to an entity or field within an entity using this format `<#E::{entities}::{entityType}::{field}::{arrayFieldName}::{arrayFieldValue}`.",
"type": "string",
"pattern": "(?U)^<#E::\\w+::[\\w'\\- .&/:+\"\\\\()$#%]+>$"
"pattern": "(?U)^<#E::\\w+::(?:[^:<>|]|:[^:<>|])+(?:::(?:[^:<>|]|:[^:<>|])+)*>$"
},
"entityName": {
"description": "Name that identifies an entity.",

View File

@ -23,6 +23,7 @@ import {
FormItemLayout,
} from '../../../../interface/FormUtils.interface';
import { generateFormFields } from '../../../../utils/formUtils';
import { escapeESReservedCharacters } from '../../../../utils/StringsUtils';
import { AddTestCaseList } from '../../AddTestCaseList/AddTestCaseList.component';
import { AddTestSuitePipelineProps } from '../AddDataQualityTest.interface';
import './add-test-suite-pipeline.style.less';
@ -142,7 +143,9 @@ const AddTestSuitePipeline = ({
]}
valuePropName="selectedTest">
<AddTestCaseList
filters={`testSuite.fullyQualifiedName:${testSuiteFQN ?? fqn}`}
filters={`testSuite.fullyQualifiedName:${escapeESReservedCharacters(
testSuiteFQN ?? fqn
)}`}
showButton={false}
/>
</Form.Item>