Fix test suite pipeline and slack alerts (#10552)

* fix: change TestSuite to implement ServiceEntityInterface

* fix: updated slack alert URL for test suites

* added  as default service type
This commit is contained in:
Teddy 2023-03-15 07:52:32 +01:00 committed by GitHub
parent c9c798e89a
commit 8acd077c23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 146 additions and 12 deletions

View File

@ -31,7 +31,7 @@ public class TestSuiteRepository extends EntityRepository<TestSuite> {
@Override @Override
public TestSuite setFields(TestSuite entity, EntityUtil.Fields fields) throws IOException { public TestSuite setFields(TestSuite entity, EntityUtil.Fields fields) throws IOException {
entity.setPipeline(fields.contains("pipelines") ? getIngestionPipeline(entity) : null); entity.setPipelines(fields.contains("pipelines") ? getIngestionPipelines(entity) : null);
return entity.withTests(fields.contains("tests") ? getTestCases(entity) : null); return entity.withTests(fields.contains("tests") ? getTestCases(entity) : null);
} }

View File

@ -180,18 +180,26 @@ public final class ChangeEventParser {
} }
public static String getEntityUrl(PUBLISH_TO publishTo, ChangeEvent event) { public static String getEntityUrl(PUBLISH_TO publishTo, ChangeEvent event) {
String fqn;
String entityType;
EntityInterface entity = (EntityInterface) event.getEntity(); EntityInterface entity = (EntityInterface) event.getEntity();
URI urlInstance = entity.getHref(); URI urlInstance = entity.getHref();
String fqn = event.getEntityFullyQualifiedName(); if (entity instanceof TestCase) {
fqn = ((TestCase) entity).getTestSuite().getFullyQualifiedName();
entityType = "test-suites";
} else {
fqn = event.getEntityFullyQualifiedName();
entityType = event.getEntityType();
}
if (Objects.nonNull(urlInstance)) { if (Objects.nonNull(urlInstance)) {
String scheme = urlInstance.getScheme(); String scheme = urlInstance.getScheme();
String host = urlInstance.getHost(); String host = urlInstance.getHost();
if (publishTo == PUBLISH_TO.SLACK || publishTo == PUBLISH_TO.GCHAT) { if (publishTo == PUBLISH_TO.SLACK || publishTo == PUBLISH_TO.GCHAT) {
return String.format("<%s://%s/%s/%s|%s>", scheme, host, event.getEntityType(), fqn, fqn); return String.format("<%s://%s/%s/%s|%s>", scheme, host, entityType, fqn, fqn);
} else if (publishTo == PUBLISH_TO.TEAMS) { } else if (publishTo == PUBLISH_TO.TEAMS) {
return String.format("[%s](%s://%s/%s/%s)", fqn, scheme, host, event.getEntityType(), fqn); return String.format("[%s](%s://%s/%s/%s)", fqn, scheme, host, entityType, fqn);
} else if (publishTo == PUBLISH_TO.EMAIL) { } else if (publishTo == PUBLISH_TO.EMAIL) {
return String.format("%s://%s/%s/%s", scheme, host, event.getEntityType(), fqn); return String.format("%s://%s/%s/%s", scheme, host, entityType, fqn);
} }
} }
return ""; return "";
@ -201,7 +209,13 @@ public final class ChangeEventParser {
SlackMessage slackMessage = new SlackMessage(); SlackMessage slackMessage = new SlackMessage();
slackMessage.setUsername(event.getUserName()); slackMessage.setUsername(event.getUserName());
if (event.getEntity() != null) { if (event.getEntity() != null) {
String headerTxt = "%s posted on " + event.getEntityType() + " %s"; String eventType;
if ((EntityInterface) event.getEntity() instanceof TestCase) {
eventType = "testSuite";
} else {
eventType = event.getEntityType();
}
String headerTxt = "%s posted on " + eventType + " %s";
String headerText = String.format(headerTxt, event.getUserName(), getEntityUrl(PUBLISH_TO.SLACK, event)); String headerText = String.format(headerTxt, event.getUserName(), getEntityUrl(PUBLISH_TO.SLACK, event));
slackMessage.setText(headerText); slackMessage.setText(headerText);
} }
@ -594,10 +608,10 @@ public final class ChangeEventParser {
if (result != null) { if (result != null) {
String format = String format =
String.format( String.format(
"Test Case %s is %s in %s/%s", "Test Case status for %s against table/column %s is %s in test suite %s",
getBold(publishTo),
getBold(publishTo), getBold(publishTo),
EntityLink.parse(testCaseEntity.getEntityLink()).getEntityFQN(), EntityLink.parse(testCaseEntity.getEntityLink()).getEntityFQN(),
getBold(publishTo),
testCaseEntity.getTestSuite().getName()); testCaseEntity.getTestSuite().getName());
return String.format(format, testCaseName, result.getTestCaseStatus()); return String.format(format, testCaseName, result.getTestCaseStatus());
} else { } else {

View File

@ -0,0 +1,93 @@
package org.openmetadata.service.alerts;
import java.net.URI;
import java.util.ArrayList;
import java.util.UUID;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openmetadata.schema.entity.data.Table;
import org.openmetadata.schema.tests.TestCase;
import org.openmetadata.schema.type.ChangeEvent;
import org.openmetadata.schema.type.Column;
import org.openmetadata.schema.type.ColumnDataType;
import org.openmetadata.schema.type.EntityReference;
import org.openmetadata.schema.type.EventType;
import org.openmetadata.service.util.ChangeEventParser;
public class AlertsURLFormattingTest {
private static ChangeEvent testCaseChangeEvent;
private static ChangeEvent tableChangeEvent;
@BeforeAll
static void setUp() {
UUID testCaseId = UUID.randomUUID();
UUID tableId = UUID.randomUUID();
testCaseChangeEvent =
new ChangeEvent()
.withEventType(EventType.ENTITY_UPDATED)
.withEntityType("TestCase")
.withEntityId(UUID.randomUUID())
.withEntityFullyQualifiedName("UnitTest.TestCase")
.withUserName("UnitTestUser")
.withTimestamp(System.currentTimeMillis())
.withEntity(
new TestCase()
.withName("TestCaseForUnitTest")
.withId(testCaseId)
.withFullyQualifiedName("UnitTest.TestCase")
.withEntityLink("<#E::table::Table.For.UnitTest>")
.withEntityFQN("Table.For.UnitTest")
.withHref(URI.create(String.format("http://localhost:8080/api/v1/testCase/%s", testCaseId)))
.withTestSuite(
new EntityReference()
.withId(UUID.randomUUID())
.withName("TestSuiteForUnitTest")
.withFullyQualifiedName("UnitTest.TestSuite")));
ArrayList<Column> columns = new ArrayList<>();
for (int i = 0; i < 3; i++) {
columns.add(
new Column()
.withName("col" + i)
.withDataType(ColumnDataType.INT)
.withFullyQualifiedName("database.TableForUnitTest.col" + i));
}
columns.add(
new Column()
.withName("col1")
.withDataType(ColumnDataType.INT)
.withFullyQualifiedName("database.TableForUnitTest.col1"));
tableChangeEvent =
new ChangeEvent()
.withEventType(EventType.ENTITY_UPDATED)
.withEntityType("table")
.withEntityId(UUID.randomUUID())
.withEntityFullyQualifiedName("UnitTestService.database.TableForUnitTest")
.withUserName("UnitTestUser")
.withTimestamp(System.currentTimeMillis())
.withEntity(
new Table()
.withId(tableId)
.withName("database.TableForUnitTest")
.withFullyQualifiedName("UnitTestService.database.TableForUnitTest")
.withHref(URI.create(String.format("http://localhost:8080/api/v1/table/%s", tableId)))
.withColumns(columns)
.withDatabase(
new EntityReference()
.withId(UUID.randomUUID())
.withName("database")
.withFullyQualifiedName("UnitTestService.database")));
}
@Test
void testAlertsSlackURLFormatting() {
String testCaseUrl = ChangeEventParser.getEntityUrl(ChangeEventParser.PUBLISH_TO.SLACK, testCaseChangeEvent);
assert testCaseUrl.equals("<http://localhost/test-suites/UnitTest.TestSuite|UnitTest.TestSuite>");
String tableUrl = ChangeEventParser.getEntityUrl(ChangeEventParser.PUBLISH_TO.SLACK, tableChangeEvent);
assert tableUrl.equals(
"<http://localhost/table/UnitTestService.database.TableForUnitTest|UnitTestService.database.TableForUnitTest>");
}
}

View File

@ -5,8 +5,22 @@
"description": "TestSuite is a set of test cases to capture data quality tests against data entities.", "description": "TestSuite is a set of test cases to capture data quality tests against data entities.",
"type": "object", "type": "object",
"javaType": "org.openmetadata.schema.tests.TestSuite", "javaType": "org.openmetadata.schema.tests.TestSuite",
"javaInterfaces": ["org.openmetadata.schema.EntityInterface"], "javaInterfaces": [
"definitions": {}, "org.openmetadata.schema.ServiceEntityInterface"
],
"definitions": {
"testSuiteConnection": {
"type": "object",
"javaInterfaces": [
"org.openmetadata.schema.ServiceConnectionEntityInterface"
],
"properties": {
"config": {
"type": "null"
}
}
}
},
"properties": { "properties": {
"id": { "id": {
"description": "Unique identifier of this test suite instance.", "description": "Unique identifier of this test suite instance.",
@ -35,11 +49,24 @@
}, },
"default": null "default": null
}, },
"pipeline": { "connection": {
"$ref": "#/definitions/testSuiteConnection"
},
"testConnectionResult": {
"$ref": "../entity/services/connections/testConnectionResult.json"
},
"pipelines": {
"description": "References to pipelines deployed for this database service to extract metadata, usage, lineage etc..", "description": "References to pipelines deployed for this database service to extract metadata, usage, lineage etc..",
"$ref": "../type/entityReference.json", "$ref": "../type/entityReference.json#/definitions/entityReferenceList",
"default": null "default": null
}, },
"serviceType": {
"description": "Type of database service such as MySQL, BigQuery, Snowflake, Redshift, Postgres...",
"javaInterfaces": ["org.openmetadata.schema.EnumInterface"],
"type": "string",
"enum": ["TestSuite"],
"default": "TestSuite"
},
"owner": { "owner": {
"description": "Owner of this TestCase definition.", "description": "Owner of this TestCase definition.",
"$ref": "../type/entityReference.json", "$ref": "../type/entityReference.json",