MINOR: revert param logic in search/list and introduce raw query param (#20244)

* fix: revert  param logic in search/list and introduce raw query param

* unskip the playwright test related to DQ

---------

Co-authored-by: Shailesh Parmar <shailesh.parmar.webdev@gmail.com>
This commit is contained in:
Teddy 2025-03-14 12:11:56 -07:00 committed by GitHub
parent 2c90a2fe6f
commit dd3382aad8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 482 additions and 431 deletions

View File

@ -1355,9 +1355,11 @@ public abstract class EntityRepository<T extends EntityInterface> {
SearchListFilter searchListFilter,
int limit,
int offset,
String q)
String q,
String queryString)
throws IOException {
return listFromSearchWithOffset(uriInfo, fields, searchListFilter, limit, offset, null, q);
return listFromSearchWithOffset(
uriInfo, fields, searchListFilter, limit, offset, null, q, queryString);
}
public ResultList<T> listFromSearchWithOffset(
@ -1367,7 +1369,8 @@ public abstract class EntityRepository<T extends EntityInterface> {
int limit,
int offset,
SearchSortFilter searchSortFilter,
String q)
String q,
String queryString)
throws IOException {
List<T> entityList = new ArrayList<>();
Long total;
@ -1375,7 +1378,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
if (limit > 0) {
SearchResultListMapper results =
searchRepository.listWithOffset(
searchListFilter, limit, offset, entityType, searchSortFilter, q);
searchListFilter, limit, offset, entityType, searchSortFilter, q, queryString);
total = results.getTotal();
for (Map<String, Object> json : results.getResults()) {
T entity = JsonUtils.readOrConvertValueLenient(json, entityClass);
@ -1385,7 +1388,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
} else {
SearchResultListMapper results =
searchRepository.listWithOffset(
searchListFilter, limit, offset, entityType, searchSortFilter, q);
searchListFilter, limit, offset, entityType, searchSortFilter, q, queryString);
total = results.getTotal();
return new ResultList<>(entityList, null, limit, total.intValue());
}

View File

@ -367,7 +367,8 @@ public abstract class EntityTimeSeriesRepository<T extends EntityTimeSeriesInter
int limit,
int offset,
SearchSortFilter searchSortFilter,
String q)
String q,
String queryString)
throws IOException {
List<T> entityList = new ArrayList<>();
long total;
@ -377,7 +378,7 @@ public abstract class EntityTimeSeriesRepository<T extends EntityTimeSeriesInter
if (limit > 0) {
SearchResultListMapper results =
searchRepository.listWithOffset(
searchListFilter, limit, offset, entityType, searchSortFilter, q);
searchListFilter, limit, offset, entityType, searchSortFilter, q, queryString);
total = results.getTotal();
for (Map<String, Object> json : results.getResults()) {
T entity = setFieldsInternal(JsonUtils.readOrConvertValue(json, entityClass), fields);
@ -389,7 +390,7 @@ public abstract class EntityTimeSeriesRepository<T extends EntityTimeSeriesInter
} else {
SearchResultListMapper results =
searchRepository.listWithOffset(
searchListFilter, limit, offset, entityType, searchSortFilter, q);
searchListFilter, limit, offset, entityType, searchSortFilter, q, queryString);
total = results.getTotal();
return new ResultList<>(entityList, null, limit, (int) total);
}

View File

@ -195,12 +195,13 @@ public abstract class EntityResource<T extends EntityInterface, K extends Entity
int offset,
SearchSortFilter searchSortFilter,
String q,
String queryString,
OperationContext operationContext,
ResourceContextInterface resourceContext)
throws IOException {
authorizer.authorize(securityContext, operationContext, resourceContext);
return repository.listFromSearchWithOffset(
uriInfo, fields, searchListFilter, limit, offset, searchSortFilter, q);
uriInfo, fields, searchListFilter, limit, offset, searchSortFilter, q, queryString);
}
public T getInternal(

View File

@ -56,12 +56,13 @@ public abstract class EntityTimeSeriesResource<
int offset,
SearchSortFilter searchSortFilter,
String q,
String queryString,
OperationContext operationContext,
ResourceContextInterface resourceContext)
throws IOException {
authorizer.authorize(securityContext, operationContext, resourceContext);
return repository.listFromSearchWithOffset(
fields, searchListFilter, limit, offset, searchSortFilter, q);
fields, searchListFilter, limit, offset, searchSortFilter, q, queryString);
}
protected ResultList<T> listInternalFromSearch(
@ -72,12 +73,13 @@ public abstract class EntityTimeSeriesResource<
int offset,
SearchSortFilter searchSortFilter,
String q,
String queryString,
List<AuthRequest> authRequests,
AuthorizationLogic authorizationLogic)
throws IOException {
authorizer.authorizeRequests(securityContext, authRequests, authorizationLogic);
return repository.listFromSearchWithOffset(
fields, searchListFilter, limit, offset, searchSortFilter, q);
fields, searchListFilter, limit, offset, searchSortFilter, q, queryString);
}
public ResultList<T> listLatestFromSearch(

View File

@ -401,7 +401,12 @@ public class TestCaseResource extends EntityResource<TestCase, TestCaseRepositor
description = "search query term to use in list",
schema = @Schema(type = "string"))
@QueryParam("q")
String q)
String q,
@Parameter(
description = "raw elasticsearch query to use in list",
schema = @Schema(type = "string"))
@QueryParam("queryString")
String queryString)
throws IOException {
if ((startTimestamp == null && endTimestamp != null)
|| (startTimestamp != null && endTimestamp == null)) {
@ -471,6 +476,7 @@ public class TestCaseResource extends EntityResource<TestCase, TestCaseRepositor
offset,
searchSortFilter,
q,
queryString,
operationContext,
resourceContextInterface);
return PIIMasker.getTestCases(tests, authorizer, securityContext);

View File

@ -304,7 +304,12 @@ public class TestCaseResultResource
description = "search query term to use in list",
schema = @Schema(type = "string"))
@QueryParam("q")
String q)
String q,
@Parameter(
description = "raw elasticsearch query to use in list",
schema = @Schema(type = "string"))
@QueryParam("queryString")
String queryString)
throws IOException {
if (latest.equals("true") && (testSuiteId == null && entityFQN == null)) {
throw new IllegalArgumentException("latest=true requires testSuiteId");
@ -345,6 +350,7 @@ public class TestCaseResultResource
offset,
new SearchSortFilter("timestamp", "desc", null, null),
q,
queryString,
authRequests,
AuthorizationLogic.ANY);
}

View File

@ -274,7 +274,12 @@ public class TestSuiteResource extends EntityResource<TestSuite, TestSuiteReposi
description = "search query term to use in list",
schema = @Schema(type = "string"))
@QueryParam("q")
String q)
String q,
@Parameter(
description = "raw elasticsearch query to use in list",
schema = @Schema(type = "string"))
@QueryParam("queryString")
String queryString)
throws IOException {
SearchSortFilter searchSortFilter =
new SearchSortFilter(sortField, sortType, sortNestedPath, sortNestedMode);
@ -300,7 +305,7 @@ public class TestSuiteResource extends EntityResource<TestSuite, TestSuiteReposi
List<AuthRequest> authRequests = getAuthRequestsForListOps();
authorizer.authorizeRequests(securityContext, authRequests, AuthorizationLogic.ANY);
return repository.listFromSearchWithOffset(
uriInfo, fields, searchListFilter, limit, offset, searchSortFilter, q);
uriInfo, fields, searchListFilter, limit, offset, searchSortFilter, q, queryString);
}
@GET

View File

@ -187,7 +187,8 @@ public interface SearchClient {
int offset,
String index,
SearchSortFilter searchSortFilter,
String q)
String q,
String queryString)
throws IOException;
SearchResultListMapper listWithDeepPagination(

View File

@ -1019,6 +1019,18 @@ public class SearchRepository {
SearchSortFilter searchSortFilter,
String q)
throws IOException {
return listWithOffset(filter, limit, offset, entityType, searchSortFilter, q, null);
}
public SearchResultListMapper listWithOffset(
SearchListFilter filter,
int limit,
int offset,
String entityType,
SearchSortFilter searchSortFilter,
String q,
String queryString)
throws IOException {
IndexMapping index = entityIndexMap.get(entityType);
return searchClient.listWithOffset(
filter.getCondition(entityType),
@ -1026,7 +1038,8 @@ public class SearchRepository {
offset,
index.getIndexName(clusterAlias),
searchSortFilter,
q);
q,
queryString);
}
public SearchResultListMapper listWithDeepPagination(

View File

@ -733,16 +733,20 @@ public class ElasticSearchClient implements SearchClient {
int offset,
String index,
SearchSortFilter searchSortFilter,
String q)
String q,
String queryString)
throws IOException {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
if (!nullOrEmpty(q)) {
XContentParser queryParser = createXContentParser(q);
searchSourceBuilder = getSearchSourceBuilder(index, q, offset, limit);
}
if (!nullOrEmpty(queryString)) {
XContentParser queryParser = createXContentParser(queryString);
searchSourceBuilder = SearchSourceBuilder.fromXContent(queryParser);
}
List<Map<String, Object>> results = new ArrayList<>();
getSearchFilter(filter, searchSourceBuilder, !nullOrEmpty(q));
getSearchFilter(filter, searchSourceBuilder, !nullOrEmpty(q) || !nullOrEmpty(queryString));
searchSourceBuilder.timeout(new TimeValue(30, TimeUnit.SECONDS));
searchSourceBuilder.from(offset);

View File

@ -717,16 +717,20 @@ public class OpenSearchClient implements SearchClient {
int offset,
String index,
SearchSortFilter searchSortFilter,
String q)
String q,
String queryString)
throws IOException {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
if (!nullOrEmpty(q)) {
XContentParser queryParser = createXContentParser(q);
searchSourceBuilder = getSearchSourceBuilder(index, q, offset, limit);
}
if (!nullOrEmpty(queryString)) {
XContentParser queryParser = createXContentParser(queryString);
searchSourceBuilder = SearchSourceBuilder.fromXContent(queryParser);
}
List<Map<String, Object>> results = new ArrayList<>();
getSearchFilter(filter, searchSourceBuilder, !nullOrEmpty(q));
getSearchFilter(filter, searchSourceBuilder, !nullOrEmpty(q) || !nullOrEmpty(queryString));
searchSourceBuilder.timeout(new TimeValue(30, TimeUnit.SECONDS));
searchSourceBuilder.from(offset);

View File

@ -953,7 +953,7 @@ public class TestCaseResourceTest extends EntityResourceTest<TestCase, CreateTes
listEntitiesFromSearch(queryParams, testCasesNum, 0, ADMIN_AUTH_HEADERS);
assertEquals(testCasesNum, allEntities.getData().size());
queryParams.put(
"q",
"queryString",
"%7B%22query%22%3A%20%7B%22term%22%3A%20%7B%22id%22%3A%20%22"
+ testCaseForEL.getId()
+ "%22%7D%7D%7D");
@ -965,6 +965,13 @@ public class TestCaseResourceTest extends EntityResourceTest<TestCase, CreateTes
.allMatch(
ts -> ts.getFullyQualifiedName().equals(testCaseForEL.getFullyQualifiedName())));
queryParams.clear();
queryParams.put("q", "test_getSimpleListFromSearchb");
allEntities = listEntitiesFromSearch(queryParams, testCasesNum, 0, ADMIN_AUTH_HEADERS);
// Note: Since the "name" field and its ngram variant are prioritized in the search query
// and the test case names are very similar, the fuzzy matching returns all test cases.
assertEquals(testCasesNum, allEntities.getData().size());
queryParams.clear();
queryParams.put("entityLink", testCaseForEL.getEntityLink());
queryParams.put("includeAllTests", "true");
@ -3664,7 +3671,7 @@ public class TestCaseResourceTest extends EntityResourceTest<TestCase, CreateTes
String id = testCaseResultResultList.getData().get(0).getId().toString();
queryParams.put(
"q",
"queryString",
"%7B%22query%22%3A%20%7B%22term%22%3A%20%7B%22id.keyword%22%3A%20%22"
+ id
+ "%22%7D%7D%7D");

View File

@ -439,7 +439,7 @@ public class TestSuiteResourceTest extends EntityResourceTest<TestSuite, CreateT
// 5. List test suite with a query
queryParams.clear();
queryParams.put(
"q",
"queryString",
"%7B%22query%22%3A%20%7B%22term%22%3A%20%7B%22id%22%3A%20%22"
+ logicalTestSuite.getId()
+ "%22%7D%7D%7D");
@ -449,6 +449,15 @@ public class TestSuiteResourceTest extends EntityResourceTest<TestSuite, CreateT
queryTestSuites.getData().stream()
.allMatch(
ts -> ts.getFullyQualifiedName().equals(logicalTestSuite.getFullyQualifiedName())));
queryParams.clear();
queryParams.put("q", logicalTestSuite.getFullyQualifiedName());
queryTestSuites = listEntitiesFromSearch(queryParams, 100, 0, ADMIN_AUTH_HEADERS);
Assertions.assertTrue(
queryTestSuites.getData().stream()
.allMatch(
ts -> ts.getFullyQualifiedName().equals(logicalTestSuite.getFullyQualifiedName())));
// 6. List test suites with a nested sort
queryParams.clear();
queryParams.put("fields", "tests");

View File

@ -18,7 +18,7 @@ import { getApiContext, redirectToHomePage, uuid } from '../../utils/common';
// use the admin user to login
test.use({ storageState: 'playwright/.auth/admin.json' });
test.skip(
test(
'TestSuite multi pipeline support',
PLAYWRIGHT_INGESTION_TAG_OBJ,
async ({ page }) => {
@ -185,7 +185,7 @@ test.skip(
}
);
test.skip(
test(
"Edit the pipeline's test case",
PLAYWRIGHT_INGESTION_TAG_OBJ,
async ({ page }) => {

View File

@ -322,7 +322,7 @@ test(
}
);
test.skip(
test(
'TestCase with Array params value',
PLAYWRIGHT_INGESTION_TAG_OBJ,
async ({ page }) => {
@ -639,417 +639,406 @@ test(
}
);
test.skip(
'TestCase filters',
PLAYWRIGHT_INGESTION_TAG_OBJ,
async ({ page }) => {
test.setTimeout(360000);
test('TestCase filters', PLAYWRIGHT_INGESTION_TAG_OBJ, async ({ page }) => {
test.setTimeout(360000);
const { apiContext, afterAction } = await getApiContext(page);
const filterTable1 = new TableClass();
const { apiContext, afterAction } = await getApiContext(page);
const filterTable1 = new TableClass();
await filterTable1.create(apiContext);
const filterTable2 = {
...filterTable1.entity,
name: `${filterTable1.entity.name}-model`,
};
const filterTable2Response = await apiContext
.post('/api/v1/tables', {
data: filterTable2,
})
.then((response) => response.json());
const domain = new Domain();
await domain.create(apiContext);
await filterTable1.create(apiContext);
const filterTable2 = {
...filterTable1.entity,
name: `${filterTable1.entity.name}-model`,
};
const filterTable2Response = await apiContext
.post('/api/v1/tables', {
data: filterTable2,
})
.then((response) => response.json());
const domain = new Domain();
await domain.create(apiContext);
// Add domain to table
await filterTable1.visitEntityPage(page);
await assignDomain(page, domain.responseData);
const testCases = [
`pw_first_table_column_count_to_be_between_${uuid()}`,
`pw_second_table_column_count_to_be_between_${uuid()}`,
`pw_third_table_column_count_to_be_between_${uuid()}`,
];
const smilerNameTestCase = testCases.map((test) => `${test}_version_2`);
await filterTable1.patch({
apiContext,
patchData: [
{
op: 'add',
path: '/tags/0',
value: {
tagFQN: 'PII.None',
name: 'None',
description: 'Non PII',
source: 'Classification',
labelType: 'Manual',
state: 'Confirmed',
},
// Add domain to table
await filterTable1.visitEntityPage(page);
await assignDomain(page, domain.responseData);
const testCases = [
`pw_first_table_column_count_to_be_between_${uuid()}`,
`pw_second_table_column_count_to_be_between_${uuid()}`,
`pw_third_table_column_count_to_be_between_${uuid()}`,
];
const smilerNameTestCase = testCases.map((test) => `${test}_version_2`);
await filterTable1.patch({
apiContext,
patchData: [
{
op: 'add',
path: '/tags/0',
value: {
tagFQN: 'PII.None',
name: 'None',
description: 'Non PII',
source: 'Classification',
labelType: 'Manual',
state: 'Confirmed',
},
{
op: 'add',
path: '/tags/1',
value: {
tagFQN: 'Tier.Tier2',
name: 'Tier2',
source: 'Classification',
labelType: 'Manual',
state: 'Confirmed',
},
},
{
op: 'add',
path: '/tags/1',
value: {
tagFQN: 'Tier.Tier2',
name: 'Tier2',
source: 'Classification',
labelType: 'Manual',
state: 'Confirmed',
},
],
},
],
});
await filterTable1.createTestSuiteAndPipelines(apiContext);
const { testSuiteData: testSuite2Response } =
await filterTable1.createTestSuiteAndPipelines(apiContext, {
basicEntityReference: filterTable2Response?.['fullyQualifiedName'],
});
await filterTable1.createTestSuiteAndPipelines(apiContext);
const { testSuiteData: testSuite2Response } =
await filterTable1.createTestSuiteAndPipelines(apiContext, {
basicEntityReference: filterTable2Response?.['fullyQualifiedName'],
});
const testCaseResult = {
result:
'Found min=10001, max=27809 vs. the expected min=90001, max=96162.',
testCaseStatus: 'Failed',
testResultValue: [
{
name: 'minValueForMaxInCol',
value: '10001',
},
{
name: 'maxValueForMaxInCol',
value: '27809',
},
],
timestamp: getCurrentMillis(),
};
for (let i = 0; i < testCases.length; i++) {
const testCase1 = await filterTable1.createTestCase(apiContext, {
name: testCases[i],
});
await filterTable1.addTestCaseResult(
apiContext,
testCase1?.['fullyQualifiedName'],
testCaseResult
);
const testCase2 = await filterTable1.createTestCase(apiContext, {
name: smilerNameTestCase[i],
entityLink: `<#E::table::${filterTable2Response?.['fullyQualifiedName']}>`,
testSuite: testSuite2Response?.['fullyQualifiedName'],
});
await filterTable1.addTestCaseResult(
apiContext,
testCase2?.['fullyQualifiedName'],
testCaseResult
);
const testCaseResult = {
result: 'Found min=10001, max=27809 vs. the expected min=90001, max=96162.',
testCaseStatus: 'Failed',
testResultValue: [
{
name: 'minValueForMaxInCol',
value: '10001',
},
{
name: 'maxValueForMaxInCol',
value: '27809',
},
],
timestamp: getCurrentMillis(),
};
for (let i = 0; i < testCases.length; i++) {
const testCase1 = await filterTable1.createTestCase(apiContext, {
name: testCases[i],
});
await filterTable1.addTestCaseResult(
apiContext,
testCase1?.['fullyQualifiedName'],
testCaseResult
);
const testCase2 = await filterTable1.createTestCase(apiContext, {
name: smilerNameTestCase[i],
entityLink: `<#E::table::${filterTable2Response?.['fullyQualifiedName']}>`,
testSuite: testSuite2Response?.['fullyQualifiedName'],
});
await filterTable1.addTestCaseResult(
apiContext,
testCase2?.['fullyQualifiedName'],
testCaseResult
);
}
const verifyFilterTestCase = async (page: Page) => {
for (const testCase of testCases) {
const element = page.locator(`[data-testid="${testCase}"]`);
await expect(element).toBeVisible();
}
};
const verifyFilterTestCase = async (page: Page) => {
for (const testCase of testCases) {
const element = page.locator(`[data-testid="${testCase}"]`);
const verifyFilter2TestCase = async (page: Page, negation = false) => {
for (const testCase of smilerNameTestCase) {
const element = page.locator(`[data-testid="${testCase}"]`);
if (negation) {
await expect(element).not.toBeVisible();
} else {
await expect(element).toBeVisible();
}
};
const verifyFilter2TestCase = async (page: Page, negation = false) => {
for (const testCase of smilerNameTestCase) {
const element = page.locator(`[data-testid="${testCase}"]`);
if (negation) {
await expect(element).not.toBeVisible();
} else {
await expect(element).toBeVisible();
}
}
};
try {
await sidebarClick(page, SidebarItem.DATA_QUALITY);
const getTestCaseListData = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.click('[data-testid="by-test-cases"]');
await getTestCaseListData;
// get all the filters
await page.click('[data-testid="advanced-filter"]');
await page.click('[value="tableFqn"]');
await page.click('[data-testid="advanced-filter"]');
await page.click('[value="testPlatforms"]');
await page.click('[data-testid="advanced-filter"]');
await page.click('[value="lastRunRange"]');
await page.click('[data-testid="advanced-filter"]');
await page.click('[value="serviceName"]');
await page.click('[data-testid="advanced-filter"]');
await page.click('[value="tags"]');
await page.click('[data-testid="advanced-filter"]');
await page.click('[value="tier"]');
// Test case search filter
const searchTestCaseResponse = page.waitForResponse(
(url) =>
url.url().includes('/api/v1/dataQuality/testCases/search/list') &&
url.url().includes(testCases[0])
);
await page.fill(
'[data-testid="test-case-container"] [data-testid="searchbar"]',
testCases[0]
);
await searchTestCaseResponse;
await expect(
page.locator(`[data-testid="${testCases[0]}"]`)
).toBeVisible();
// clear the search filter
const getTestCaseResponse = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.locator('.ant-input-clear-icon').click();
await getTestCaseResponse;
// Test case filter by service name
const serviceResponse = page.waitForResponse(
'/api/v1/search/query?q=*index=database_service_search_index*'
);
await page.fill('#serviceName', filterTable1.service.name);
await serviceResponse;
const testCaseByServiceName = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*serviceName=${filterTable1.service.name}*`
);
await page
.locator('.ant-select-dropdown')
.filter({
hasNot: page.locator('.ant-select-dropdown-hidden'),
has: page.locator(`[data-testid="${filterTable1.service.name}"]`),
})
.click();
await testCaseByServiceName;
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page);
// remove service filter
await page.click('[data-testid="advanced-filter"]');
const getTestCase = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.click('[value="serviceName"]');
await getTestCase;
// Test case filter by Tags
const tagResponse = page.waitForResponse(
'/api/v1/search/query?q=*index=tag_search_index*'
);
await page
.getByTestId('tags-select-filter')
.locator('div')
.filter({ hasText: 'Tags' })
.click();
await page.fill('#tags', 'PII.None');
await tagResponse;
const getTestCaseByTag = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*tags=PII.None*'
);
await page
.locator('.ant-select-dropdown')
.filter({
hasNot: page.locator('.ant-select-dropdown-hidden'),
has: page.locator(`[data-testid="PII.None"]`),
})
.click();
await getTestCaseByTag;
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page, true);
// remove tags filter
await page.click('[data-testid="advanced-filter"]');
const getTestCaseWithoutTag = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.click('[value="tags"]');
await getTestCaseWithoutTag;
// Test case filter by Tier
await page.click('#tier');
await page.fill('#tier', 'Tier2');
await page.waitForLoadState('domcontentloaded');
const getTestCaseByTier = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*tier=Tier.Tier2*'
);
await page.getByTestId('Tier.Tier2').getByText('Tier.Tier2').click();
await getTestCaseByTier;
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page, true);
// remove tier filter
await page.click('[data-testid="advanced-filter"]');
const getTestCaseWithoutTier = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.click('[value="tier"]');
await getTestCaseWithoutTier;
// Test case filter by table name
const tableSearchResponse = page.waitForResponse(
`/api/v1/search/query?q=*index=table_search_index*`
);
await page.fill('#tableFqn', filterTable1.entity.name);
await tableSearchResponse;
const getTestCaseByTable = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*entityLink=*${filterTable1.entity.name}*`
);
await page
.getByTestId(filterTable1.entityResponseData?.['fullyQualifiedName'])
.click();
await getTestCaseByTable;
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page, true);
// Test case filter by test type column
const testCaseTypeByColumn = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testCaseType=column*`
);
await page.getByTestId('test-case-type-select-filter').click();
await page.getByTitle('Column').click();
await testCaseTypeByColumn;
await expect(
page.locator('[data-testid="search-error-placeholder"]')
).toBeVisible();
// Test case filter by test type table
const testCaseTypeByTable = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testCaseType=table*`
);
await page.getByTestId('test-case-type-select-filter').click();
await page
.locator('.ant-select-dropdown')
.filter({
hasNot: page.locator('.ant-select-dropdown-hidden'),
has: page.locator(`[title="Table"]`),
hasText: 'Table',
})
.click();
await testCaseTypeByTable;
await verifyFilterTestCase(page);
// Test case filter by test type all
const testCaseTypeByAll = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testCaseType=all*`
);
await page.getByTestId('test-case-type-select-filter').click();
await page.getByTitle('All').nth(1).click();
await testCaseTypeByAll;
// Test case filter by status
const testCaseStatusBySuccess = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testCaseStatus=Success*`
);
await page.getByTestId('status-select-filter').click();
await page.getByTitle('Success').click();
await testCaseStatusBySuccess;
await expect(
page.locator('[data-testid="search-error-placeholder"]')
).toBeVisible();
// Test case filter by status
const testCaseStatusByFailed = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testCaseStatus=Failed*`
);
await page.getByTestId('status-select-filter').click();
await page.getByTitle('Failed').click();
await testCaseStatusByFailed;
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page, true);
// Test case filter by platform
const testCasePlatformByDBT = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testPlatforms=DBT*`
);
await page.getByTestId('platform-select-filter').click();
await page.getByTitle('DBT').click();
await testCasePlatformByDBT;
await expect(
page.locator('[data-testid="search-error-placeholder"]')
).toBeVisible();
const getTestCaseWithoutPlatform = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page
.getByTestId('platform-select-filter')
.locator('.ant-select-clear')
.click();
await getTestCaseWithoutPlatform;
const testCasePlatformByOpenMetadata = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testPlatforms=OpenMetadata*`
);
await page.getByTestId('platform-select-filter').click();
await page.getByTitle('OpenMetadata').click();
await testCasePlatformByOpenMetadata;
await clickOutside(page);
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page, true);
const url = page.url();
await page.reload();
await expect(page.url()).toBe(url);
await page.getByTestId('advanced-filter').click();
await page.click('[value="testPlatforms"]');
await page.waitForTimeout(200);
await expect(
page.getByTestId('platform-select-filter')
).not.toBeVisible();
await page.reload();
await expect(page.locator('[value="tier"]')).not.toBeVisible();
// Apply domain globally
await page.getByTestId('domain-dropdown').click();
await page
.getByTestId(`tag-${domain.responseData.fullyQualifiedName}`)
.click();
await page.getByTestId('saveAssociatedTag').click();
await sidebarClick(page, SidebarItem.DATA_QUALITY);
const getTestCaseList = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.click('[data-testid="by-test-cases"]');
await getTestCaseList;
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page, true);
await visitDataQualityTab(page, filterTable1);
const searchTestCase = page.waitForResponse(
(url) =>
url.url().includes('/api/v1/dataQuality/testCases/search/list') &&
url.url().includes(testCases[0])
);
await page
.getByTestId('table-profiler-container')
.getByTestId('searchbar')
.fill(testCases[0]);
await searchTestCase;
await expect(
page.locator(`[data-testid="${testCases[0]}"]`)
).toBeVisible();
await expect(
page.locator(`[data-testid="${testCases[1]}"]`)
).not.toBeVisible();
await expect(
page.locator(`[data-testid="${testCases[2]}"]`)
).not.toBeVisible();
} finally {
await filterTable1.delete(apiContext);
await domain.delete(apiContext);
await afterAction();
}
};
try {
await sidebarClick(page, SidebarItem.DATA_QUALITY);
const getTestCaseListData = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.click('[data-testid="by-test-cases"]');
await getTestCaseListData;
// get all the filters
await page.click('[data-testid="advanced-filter"]');
await page.click('[value="tableFqn"]');
await page.click('[data-testid="advanced-filter"]');
await page.click('[value="testPlatforms"]');
await page.click('[data-testid="advanced-filter"]');
await page.click('[value="lastRunRange"]');
await page.click('[data-testid="advanced-filter"]');
await page.click('[value="serviceName"]');
await page.click('[data-testid="advanced-filter"]');
await page.click('[value="tags"]');
await page.click('[data-testid="advanced-filter"]');
await page.click('[value="tier"]');
// Test case search filter
const searchTestCaseResponse = page.waitForResponse(
(url) =>
url.url().includes('/api/v1/dataQuality/testCases/search/list') &&
url.url().includes(testCases[0])
);
await page.fill(
'[data-testid="test-case-container"] [data-testid="searchbar"]',
testCases[0]
);
await searchTestCaseResponse;
await expect(page.locator(`[data-testid="${testCases[0]}"]`)).toBeVisible();
// clear the search filter
const getTestCaseResponse = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.locator('.ant-input-clear-icon').click();
await getTestCaseResponse;
// Test case filter by service name
const serviceResponse = page.waitForResponse(
'/api/v1/search/query?q=*index=database_service_search_index*'
);
await page.fill('#serviceName', filterTable1.service.name);
await serviceResponse;
const testCaseByServiceName = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*serviceName=${filterTable1.service.name}*`
);
await page
.locator('.ant-select-dropdown')
.filter({
hasNot: page.locator('.ant-select-dropdown-hidden'),
has: page.locator(`[data-testid="${filterTable1.service.name}"]`),
})
.click();
await testCaseByServiceName;
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page);
// remove service filter
await page.click('[data-testid="advanced-filter"]');
const getTestCase = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.click('[value="serviceName"]');
await getTestCase;
// Test case filter by Tags
const tagResponse = page.waitForResponse(
'/api/v1/search/query?q=*index=tag_search_index*'
);
await page
.getByTestId('tags-select-filter')
.locator('div')
.filter({ hasText: 'Tags' })
.click();
await page.fill('#tags', 'PII.None');
await tagResponse;
const getTestCaseByTag = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*tags=PII.None*'
);
await page
.locator('.ant-select-dropdown')
.filter({
hasNot: page.locator('.ant-select-dropdown-hidden'),
has: page.locator(`[data-testid="PII.None"]`),
})
.click();
await getTestCaseByTag;
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page, true);
// remove tags filter
await page.click('[data-testid="advanced-filter"]');
const getTestCaseWithoutTag = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.click('[value="tags"]');
await getTestCaseWithoutTag;
// Test case filter by Tier
await page.click('#tier');
await page.fill('#tier', 'Tier2');
await page.waitForLoadState('domcontentloaded');
const getTestCaseByTier = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*tier=Tier.Tier2*'
);
await page.getByTestId('Tier.Tier2').getByText('Tier.Tier2').click();
await getTestCaseByTier;
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page, true);
// remove tier filter
await page.click('[data-testid="advanced-filter"]');
const getTestCaseWithoutTier = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.click('[value="tier"]');
await getTestCaseWithoutTier;
// Test case filter by table name
const tableSearchResponse = page.waitForResponse(
`/api/v1/search/query?q=*index=table_search_index*`
);
await page.fill('#tableFqn', filterTable1.entity.name);
await tableSearchResponse;
const getTestCaseByTable = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*entityLink=*${filterTable1.entity.name}*`
);
await page
.getByTestId(filterTable1.entityResponseData?.['fullyQualifiedName'])
.click();
await getTestCaseByTable;
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page, true);
// Test case filter by test type column
const testCaseTypeByColumn = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testCaseType=column*`
);
await page.getByTestId('test-case-type-select-filter').click();
await page.getByTitle('Column').click();
await testCaseTypeByColumn;
await expect(
page.locator('[data-testid="search-error-placeholder"]')
).toBeVisible();
// Test case filter by test type table
const testCaseTypeByTable = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testCaseType=table*`
);
await page.getByTestId('test-case-type-select-filter').click();
await page
.locator('.ant-select-dropdown')
.filter({
hasNot: page.locator('.ant-select-dropdown-hidden'),
has: page.locator(`[title="Table"]`),
hasText: 'Table',
})
.click();
await testCaseTypeByTable;
await verifyFilterTestCase(page);
// Test case filter by test type all
const testCaseTypeByAll = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testCaseType=all*`
);
await page.getByTestId('test-case-type-select-filter').click();
await page.getByTitle('All').nth(1).click();
await testCaseTypeByAll;
// Test case filter by status
const testCaseStatusBySuccess = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testCaseStatus=Success*`
);
await page.getByTestId('status-select-filter').click();
await page.getByTitle('Success').click();
await testCaseStatusBySuccess;
await expect(
page.locator('[data-testid="search-error-placeholder"]')
).toBeVisible();
// Test case filter by status
const testCaseStatusByFailed = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testCaseStatus=Failed*`
);
await page.getByTestId('status-select-filter').click();
await page.getByTitle('Failed').click();
await testCaseStatusByFailed;
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page, true);
// Test case filter by platform
const testCasePlatformByDBT = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testPlatforms=DBT*`
);
await page.getByTestId('platform-select-filter').click();
await page.getByTitle('DBT').click();
await testCasePlatformByDBT;
await expect(
page.locator('[data-testid="search-error-placeholder"]')
).toBeVisible();
const getTestCaseWithoutPlatform = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page
.getByTestId('platform-select-filter')
.locator('.ant-select-clear')
.click();
await getTestCaseWithoutPlatform;
const testCasePlatformByOpenMetadata = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?*testPlatforms=OpenMetadata*`
);
await page.getByTestId('platform-select-filter').click();
await page.getByTitle('OpenMetadata').click();
await testCasePlatformByOpenMetadata;
await clickOutside(page);
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page, true);
const url = page.url();
await page.reload();
await expect(page.url()).toBe(url);
await page.getByTestId('advanced-filter').click();
await page.click('[value="testPlatforms"]');
await page.waitForTimeout(200);
await expect(page.getByTestId('platform-select-filter')).not.toBeVisible();
await page.reload();
await expect(page.locator('[value="tier"]')).not.toBeVisible();
// Apply domain globally
await page.getByTestId('domain-dropdown').click();
await page
.getByTestId(`tag-${domain.responseData.fullyQualifiedName}`)
.click();
await page.getByTestId('saveAssociatedTag').click();
await sidebarClick(page, SidebarItem.DATA_QUALITY);
const getTestCaseList = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.click('[data-testid="by-test-cases"]');
await getTestCaseList;
await verifyFilterTestCase(page);
await verifyFilter2TestCase(page, true);
await visitDataQualityTab(page, filterTable1);
const searchTestCase = page.waitForResponse(
(url) =>
url.url().includes('/api/v1/dataQuality/testCases/search/list') &&
url.url().includes(testCases[0])
);
await page
.getByTestId('table-profiler-container')
.getByTestId('searchbar')
.fill(testCases[0]);
await searchTestCase;
await expect(page.locator(`[data-testid="${testCases[0]}"]`)).toBeVisible();
await expect(
page.locator(`[data-testid="${testCases[1]}"]`)
).not.toBeVisible();
await expect(
page.locator(`[data-testid="${testCases[2]}"]`)
).not.toBeVisible();
} finally {
await filterTable1.delete(apiContext);
await domain.delete(apiContext);
await afterAction();
}
);
});

View File

@ -64,7 +64,7 @@ test.beforeEach(async ({ page }) => {
await redirectToHomePage(page);
});
test.skip('Logical TestSuite', async ({ page }) => {
test('Logical TestSuite', async ({ page }) => {
test.slow();
const NEW_TEST_SUITE = {