From 907e0d38b84b7deca6e10d307aed7ba69898e99e Mon Sep 17 00:00:00 2001 From: RounakDhillon <162090200+RounakDhillon@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:45:38 +0530 Subject: [PATCH 1/5] Docs: updatinggettingstarted (#18045) Co-authored-by: Rounak Dhillon --- .../getting-started/day-1/database-service-setup.md | 1 - .../how-to-guides/getting-started/day-1/index.md | 1 - .../v1.5.x/how-to-guides/getting-started/index.md | 4 ++-- .../content/v1.5.x/how-to-guides/index.md | 13 +++++++++++++ .../getting-started/day-1/database-service-setup.md | 1 - .../how-to-guides/getting-started/day-1/index.md | 1 - .../how-to-guides/getting-started/index.md | 4 ++-- .../content/v1.6.x-SNAPSHOT/how-to-guides/index.md | 13 +++++++++++++ 8 files changed, 30 insertions(+), 8 deletions(-) diff --git a/openmetadata-docs/content/v1.5.x/how-to-guides/getting-started/day-1/database-service-setup.md b/openmetadata-docs/content/v1.5.x/how-to-guides/getting-started/day-1/database-service-setup.md index 8ddf6e0b17ff..a67d0dc90c28 100644 --- a/openmetadata-docs/content/v1.5.x/how-to-guides/getting-started/day-1/database-service-setup.md +++ b/openmetadata-docs/content/v1.5.x/how-to-guides/getting-started/day-1/database-service-setup.md @@ -1,7 +1,6 @@ --- title: Database service setup slug: /how-to-guides/getting-started/day-1/database-service-setup -collate: true --- ## Setting Up a Database Service for Metadata Extraction diff --git a/openmetadata-docs/content/v1.5.x/how-to-guides/getting-started/day-1/index.md b/openmetadata-docs/content/v1.5.x/how-to-guides/getting-started/day-1/index.md index 0b0877b24ebf..87bd8c564e38 100644 --- a/openmetadata-docs/content/v1.5.x/how-to-guides/getting-started/day-1/index.md +++ b/openmetadata-docs/content/v1.5.x/how-to-guides/getting-started/day-1/index.md @@ -1,7 +1,6 @@ --- title: Day 1 slug: /how-to-guides/getting-started/day-1 -collate: true --- # Getting Started: Day 1 diff --git a/openmetadata-docs/content/v1.5.x/how-to-guides/getting-started/index.md b/openmetadata-docs/content/v1.5.x/how-to-guides/getting-started/index.md index ad0a3aea8868..d1044aa836fd 100644 --- a/openmetadata-docs/content/v1.5.x/how-to-guides/getting-started/index.md +++ b/openmetadata-docs/content/v1.5.x/how-to-guides/getting-started/index.md @@ -7,7 +7,7 @@ slug: /how-to-guides/getting-started Welcome to OpenMetadata's unified platform for data discovery, observability, and governance. Our platform centralizes all data context to help you build high-quality data and AI assets. This guide provides the necessary information to set up your OpenMetadata environment in 30 minutes. -## How Does Collate Work? +## How Does OpenMetadata Work? OpenMetadata is designed to support both technical and non-technical data practitioners across various use cases, including data discovery, lineage, observability, quality, collaboration, governance, and insights. @@ -18,7 +18,7 @@ The platform’s native collaboration features support shared workflows, enablin ## Key Features of OpenMetadata -Before we get started, here’s a quick summary of some of Collate’s main features: +Before we get started, here’s a quick summary of some of OpenMetadata’s main features: ### Discovery - Integrated catalog, data quality, and glossary diff --git a/openmetadata-docs/content/v1.5.x/how-to-guides/index.md b/openmetadata-docs/content/v1.5.x/how-to-guides/index.md index fcc33a8cc675..84af90a4eb6a 100644 --- a/openmetadata-docs/content/v1.5.x/how-to-guides/index.md +++ b/openmetadata-docs/content/v1.5.x/how-to-guides/index.md @@ -5,6 +5,19 @@ slug: /how-to-guides # How-to Guides +## Getting Started + +Set up and explore OpenMetadata's core features, from basic configuration to advanced functionalities, for a seamless onboarding experience. + +{% tilesContainer %} +{% tile + title="Getting Started" + description="Unlock metadata insights for informed business decisions." + link="/how-to-guides/getting-started" + icon="discovery" +/%} +{% /tilesContainer %} + The How-to Guides will give you a walk through on accomplishing the basic to the most advanced things in OpenMetadata. These step-by-step guides will help get an overview of the features and also help explore the various functionalities. ## Features in OpenMetadata diff --git a/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/getting-started/day-1/database-service-setup.md b/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/getting-started/day-1/database-service-setup.md index 826148ca706a..c8310a1dfff4 100644 --- a/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/getting-started/day-1/database-service-setup.md +++ b/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/getting-started/day-1/database-service-setup.md @@ -1,7 +1,6 @@ --- title: Database service setup slug: /how-to-guides/getting-started/day-1/database-service-setup -collate: true --- ## Setting Up a Database Service for Metadata Extraction diff --git a/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/getting-started/day-1/index.md b/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/getting-started/day-1/index.md index 319b8b528a87..3788f95015c8 100644 --- a/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/getting-started/day-1/index.md +++ b/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/getting-started/day-1/index.md @@ -1,7 +1,6 @@ --- title: Day 1 slug: /how-to-guides/getting-started/day-1 -collate: true --- # Getting Started: Day 1 diff --git a/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/getting-started/index.md b/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/getting-started/index.md index ad0a3aea8868..d1044aa836fd 100644 --- a/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/getting-started/index.md +++ b/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/getting-started/index.md @@ -7,7 +7,7 @@ slug: /how-to-guides/getting-started Welcome to OpenMetadata's unified platform for data discovery, observability, and governance. Our platform centralizes all data context to help you build high-quality data and AI assets. This guide provides the necessary information to set up your OpenMetadata environment in 30 minutes. -## How Does Collate Work? +## How Does OpenMetadata Work? OpenMetadata is designed to support both technical and non-technical data practitioners across various use cases, including data discovery, lineage, observability, quality, collaboration, governance, and insights. @@ -18,7 +18,7 @@ The platform’s native collaboration features support shared workflows, enablin ## Key Features of OpenMetadata -Before we get started, here’s a quick summary of some of Collate’s main features: +Before we get started, here’s a quick summary of some of OpenMetadata’s main features: ### Discovery - Integrated catalog, data quality, and glossary diff --git a/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/index.md b/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/index.md index fcc33a8cc675..84af90a4eb6a 100644 --- a/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/index.md +++ b/openmetadata-docs/content/v1.6.x-SNAPSHOT/how-to-guides/index.md @@ -5,6 +5,19 @@ slug: /how-to-guides # How-to Guides +## Getting Started + +Set up and explore OpenMetadata's core features, from basic configuration to advanced functionalities, for a seamless onboarding experience. + +{% tilesContainer %} +{% tile + title="Getting Started" + description="Unlock metadata insights for informed business decisions." + link="/how-to-guides/getting-started" + icon="discovery" +/%} +{% /tilesContainer %} + The How-to Guides will give you a walk through on accomplishing the basic to the most advanced things in OpenMetadata. These step-by-step guides will help get an overview of the features and also help explore the various functionalities. ## Features in OpenMetadata From 85519cf280aa1f846fc3d29e7a7a24c44107bad2 Mon Sep 17 00:00:00 2001 From: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:59:24 +0530 Subject: [PATCH 2/5] minor(ui): fix role page size from 10 to 50 (#18049) --- nativeProject | 1 + .../Bot/BotDetails/BotDetails.component.tsx | 23 +++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) create mode 160000 nativeProject diff --git a/nativeProject b/nativeProject new file mode 160000 index 000000000000..b522464e96cf --- /dev/null +++ b/nativeProject @@ -0,0 +1 @@ +Subproject commit b522464e96cfa4302c0dd565ee8946df0bf13033 diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Bot/BotDetails/BotDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Bot/BotDetails/BotDetails.component.tsx index 861f7605bed1..8c3857e4f0c3 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Bot/BotDetails/BotDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Bot/BotDetails/BotDetails.component.tsx @@ -26,27 +26,26 @@ import { AxiosError } from 'axios'; import { toLower } from 'lodash'; import React, { FC, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { ReactComponent as IconBotProfile } from '../../../../assets/svg/bot-profile.svg'; import { ReactComponent as EditIcon } from '../../../../assets/svg/edit-new.svg'; -import { TERM_ADMIN } from '../../../../constants/constants'; +import { PAGE_SIZE_LARGE, TERM_ADMIN } from '../../../../constants/constants'; import { GlobalSettingOptions } from '../../../../constants/GlobalSettings.constants'; +import { useLimitStore } from '../../../../context/LimitsProvider/useLimitsStore'; +import { EntityType } from '../../../../enums/entity.enum'; import { Role } from '../../../../generated/entity/teams/role'; -import { getRoles } from '../../../../rest/userAPI'; +import { getRoles } from '../../../../rest/rolesAPIV1'; import { getEntityName } from '../../../../utils/EntityUtils'; import { getSettingPath } from '../../../../utils/RouterUtils'; import { showErrorToast } from '../../../../utils/ToastUtils'; +import DescriptionV1 from '../../../common/EntityDescription/DescriptionV1'; import InheritedRolesCard from '../../../common/InheritedRolesCard/InheritedRolesCard.component'; import RolesCard from '../../../common/RolesCard/RolesCard.component'; import TitleBreadcrumb from '../../../common/TitleBreadcrumb/TitleBreadcrumb.component'; import PageLayoutV1 from '../../../PageLayoutV1/PageLayoutV1'; +import AccessTokenCard from '../../Users/AccessTokenCard/AccessTokenCard.component'; import './bot-details.less'; import { BotsDetailProps } from './BotDetails.interfaces'; -import { ReactComponent as IconBotProfile } from '../../../../assets/svg/bot-profile.svg'; -import { useLimitStore } from '../../../../context/LimitsProvider/useLimitsStore'; -import { EntityType } from '../../../../enums/entity.enum'; -import DescriptionV1 from '../../../common/EntityDescription/DescriptionV1'; -import AccessTokenCard from '../../Users/AccessTokenCard/AccessTokenCard.component'; - const BotDetails: FC = ({ botData, botUserData, @@ -88,7 +87,13 @@ const BotDetails: FC = ({ const fetchRoles = async () => { try { - const { data } = await getRoles(); + const { data } = await getRoles( + '', + undefined, + undefined, + false, + PAGE_SIZE_LARGE + ); setRoles(data); } catch (err) { setRoles([]); From dcde5009693db4c010e4d29e5a1ee46711eda4bc Mon Sep 17 00:00:00 2001 From: Aniket Katkar Date: Mon, 30 Sep 2024 17:24:02 +0530 Subject: [PATCH 3/5] Mark the pipeline alert test as slow (#18046) --- .../playwright/e2e/Flow/ObservabilityAlerts.spec.ts | 2 ++ .../src/main/resources/ui/playwright/utils/alert.ts | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/ObservabilityAlerts.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/ObservabilityAlerts.spec.ts index c17605b8b9f7..64462e71bb61 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/ObservabilityAlerts.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/ObservabilityAlerts.spec.ts @@ -105,6 +105,8 @@ test.describe('Observability Alert Flow', () => { }); test('Pipeline Alert', async ({ page }) => { + test.slow(); + const ALERT_NAME = generateAlertName(); await test.step('Create alert', async () => { diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/alert.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/alert.ts index 1618c6f74b4f..5c450db653c5 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/alert.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/alert.ts @@ -20,6 +20,9 @@ import { } from '../constant/alert.interface'; import { DELETE_TERM } from '../constant/common'; import { SidebarItem } from '../constant/sidebar'; +import { Domain } from '../support/domain/Domain'; +import { DashboardClass } from '../support/entity/DashboardClass'; +import { UserClass } from '../support/user/UserClass'; import { clickOutside, descriptionBox, @@ -643,10 +646,10 @@ export const addMultipleFilters = async ({ dashboard, }: { page: Page; - user1; - user2; - domain; - dashboard; + user1: UserClass; + user2: UserClass; + domain: Domain; + dashboard: DashboardClass; }) => { // Add owner filter await page.click('[data-testid="add-filters"]'); From daa03456443bc22a538e41bd9bf5e0f6b49d283e Mon Sep 17 00:00:00 2001 From: Akash-Jain <15995028+akash-jain-10@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:50:18 +0530 Subject: [PATCH 4/5] hotfix: Remove `nativeProject` --- nativeProject | 1 - 1 file changed, 1 deletion(-) delete mode 160000 nativeProject diff --git a/nativeProject b/nativeProject deleted file mode 160000 index b522464e96cf..000000000000 --- a/nativeProject +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b522464e96cfa4302c0dd565ee8946df0bf13033 From 9552886f296058f962587c018dc9b0c29f183a78 Mon Sep 17 00:00:00 2001 From: Teddy Date: Mon, 30 Sep 2024 14:21:41 +0200 Subject: [PATCH 5/5] GEN 1211 - Added TTResp and TTReso metrics (#18033) * fix import issue * feat: compute test case resolution metrics * feat: added index key to resolution index --------- Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> --- .../service/jdbi3/CollectionDAO.java | 6 ++ .../TestCaseResolutionStatusRepository.java | 50 +++++++++++++++++ ..._case_resolution_status_index_mapping.json | 17 ++++++ ..._case_resolution_status_index_mapping.json | 17 ++++++ ..._case_resolution_status_index_mapping.json | 17 ++++++ .../dqtests/TestCaseResourceTest.java | 56 ++++++++++--------- .../tests/testCaseResolutionStatus.json | 21 +++++++ 7 files changed, 158 insertions(+), 26 deletions(-) diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/CollectionDAO.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/CollectionDAO.java index 2c8c21d55337..ae06d02bbc10 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/CollectionDAO.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/CollectionDAO.java @@ -4374,6 +4374,12 @@ default String getTimeSeriesTableName() { + "WHERE stateId = :stateId ORDER BY timestamp DESC") List listTestCaseResolutionStatusesForStateId(@Bind("stateId") String stateId); + @SqlQuery( + value = + "SELECT json FROM test_case_resolution_status_time_series " + + "WHERE stateId = :stateId ORDER BY timestamp ASC LIMIT 1") + String listFirstTestCaseResolutionStatusesForStateId(@Bind("stateId") String stateId); + @SqlUpdate( "DELETE FROM test_case_resolution_status_time_series WHERE entityFQNHash = :entityFQNHash") void delete(@BindFQN("entityFQNHash") String entityFQNHash); diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TestCaseResolutionStatusRepository.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TestCaseResolutionStatusRepository.java index 628e2a287159..564fecc64807 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TestCaseResolutionStatusRepository.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TestCaseResolutionStatusRepository.java @@ -24,6 +24,7 @@ import org.openmetadata.schema.entity.teams.User; import org.openmetadata.schema.tests.TestCase; import org.openmetadata.schema.tests.type.Assigned; +import org.openmetadata.schema.tests.type.Metric; import org.openmetadata.schema.tests.type.Resolved; import org.openmetadata.schema.tests.type.Severity; import org.openmetadata.schema.tests.type.TestCaseResolutionStatus; @@ -49,6 +50,8 @@ public class TestCaseResolutionStatusRepository extends EntityTimeSeriesRepository { public static final String COLLECTION_PATH = "/v1/dataQuality/testCases/testCaseIncidentStatus"; + public static final String TIME_TO_RESPONSE = "timeToResponse"; + public static final String TIME_TO_RESOLUTION = "timeToResolution"; public TestCaseResolutionStatusRepository() { super( @@ -75,6 +78,21 @@ public ResultList listTestCaseResolutionStatusesForSta return getResultList(testCaseResolutionStatuses, null, null, testCaseResolutionStatuses.size()); } + private TestCaseResolutionStatus listFirstTestCaseResolutionStatusForStateId(UUID stateId) { + String json = + ((CollectionDAO.TestCaseResolutionStatusTimeSeriesDAO) timeSeriesDao) + .listFirstTestCaseResolutionStatusesForStateId(stateId.toString()); + + if (json == null) { + return null; + } + + TestCaseResolutionStatus testCaseResolutionStatus = + JsonUtils.readValue(json, TestCaseResolutionStatus.class); + setInheritedFields(testCaseResolutionStatus); + return testCaseResolutionStatus; + } + public RestUtil.PatchResponse patch( UUID id, JsonPatch patch, String user) throws IntrospectionException, InvocationTargetException, IllegalAccessException { @@ -190,6 +208,7 @@ public void storeInternal( : recordEntity.getSeverity()); } + setResolutionMetrics(lastIncident, recordEntity); inferIncidentSeverity(recordEntity); switch (recordEntity.getTestCaseResolutionStatusType()) { @@ -438,4 +457,35 @@ protected static UUID getOrCreateIncident(TestCase testCase, String updatedBy) { return incident.getStateId(); } + + private void setResolutionMetrics( + TestCaseResolutionStatus lastIncident, TestCaseResolutionStatus newIncident) { + List metrics = new ArrayList<>(); + if (lastIncident == null) return; + + if (lastIncident.getTestCaseResolutionStatusType().equals(TestCaseResolutionStatusTypes.New) + && !newIncident + .getTestCaseResolutionStatusType() + .equals(TestCaseResolutionStatusTypes.Resolved)) { + // Time to response is New (1st step in the workflow) -> [Any status but Resolved (Last step + // in the workflow)] + long timeToResponse = newIncident.getTimestamp() - lastIncident.getTimestamp(); + Metric metric = new Metric().withName(TIME_TO_RESPONSE).withValue((double) timeToResponse); + metrics.add(metric); + } + + if (newIncident + .getTestCaseResolutionStatusType() + .equals(TestCaseResolutionStatusTypes.Resolved)) { + TestCaseResolutionStatus firstIncidentInWorkflow = + listFirstTestCaseResolutionStatusForStateId(newIncident.getStateId()); + if (firstIncidentInWorkflow != null) { + long timeToResolution = newIncident.getTimestamp() - firstIncidentInWorkflow.getTimestamp(); + Metric metric = + new Metric().withName(TIME_TO_RESOLUTION).withValue((double) timeToResolution); + metrics.add(metric); + } + } + if (!metrics.isEmpty()) newIncident.setMetrics(metrics); + } } diff --git a/openmetadata-service/src/main/resources/elasticsearch/en/test_case_resolution_status_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/en/test_case_resolution_status_index_mapping.json index 9a36d0b16600..0dedb13a5488 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/en/test_case_resolution_status_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/en/test_case_resolution_status_index_mapping.json @@ -200,6 +200,23 @@ } } }, + "metrics": { + "type": "nested", + "properties": { + "name": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "value": { + "type": "float" + } + } + }, "updatedBy": { "properties": { "id": { diff --git a/openmetadata-service/src/main/resources/elasticsearch/jp/test_case_resolution_status_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/jp/test_case_resolution_status_index_mapping.json index 488b651b0ad2..66a6c27f26fc 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/jp/test_case_resolution_status_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/jp/test_case_resolution_status_index_mapping.json @@ -204,6 +204,23 @@ } } }, + "metrics": { + "type": "nested", + "properties": { + "name": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "value": { + "type": "float" + } + } + }, "updatedBy": { "properties": { "id": { diff --git a/openmetadata-service/src/main/resources/elasticsearch/zh/test_case_resolution_status_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/zh/test_case_resolution_status_index_mapping.json index 49c20ae0c9ce..394290a70731 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/zh/test_case_resolution_status_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/zh/test_case_resolution_status_index_mapping.json @@ -194,6 +194,23 @@ } } }, + "metrics": { + "type": "nested", + "properties": { + "name": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "value": { + "type": "float" + } + } + }, "updatedBy": { "properties": { "id": { diff --git a/openmetadata-service/src/test/java/org/openmetadata/service/resources/dqtests/TestCaseResourceTest.java b/openmetadata-service/src/test/java/org/openmetadata/service/resources/dqtests/TestCaseResourceTest.java index 26e2cff21a73..7f4c06816c32 100644 --- a/openmetadata-service/src/test/java/org/openmetadata/service/resources/dqtests/TestCaseResourceTest.java +++ b/openmetadata-service/src/test/java/org/openmetadata/service/resources/dqtests/TestCaseResourceTest.java @@ -14,7 +14,6 @@ package org.openmetadata.service.resources.dqtests; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; -import static javax.ws.rs.core.Response.Status.CREATED; import static javax.ws.rs.core.Response.Status.FORBIDDEN; import static javax.ws.rs.core.Response.Status.NOT_FOUND; import static javax.ws.rs.core.Response.Status.OK; @@ -334,7 +333,7 @@ void getTestCaseWithResult(TestInfo test) throws IOException, ParseException { new CreateTestCaseResult() .withResult("tested") .withTestCaseStatus(TestCaseStatus.Success) - .withTimestamp(TestUtils.dateToTimestamp(String.format("2021-09-11"))); + .withTimestamp(TestUtils.dateToTimestamp("2021-09-11")); TestCaseResult testCaseResult = postTestCaseResult( testCase.getFullyQualifiedName(), createTestCaseResult, ADMIN_AUTH_HEADERS); @@ -359,7 +358,7 @@ void getTestCaseWithResult(TestInfo test) throws IOException, ParseException { new CreateTestCaseResult() .withResult("tested") .withTestCaseStatus(TestCaseStatus.Success) - .withTimestamp(TestUtils.dateToTimestamp(String.format("2021-09-01"))); + .withTimestamp(TestUtils.dateToTimestamp("2021-09-01")); postTestCaseResult(testCase.getFullyQualifiedName(), createTestCaseResult, ADMIN_AUTH_HEADERS); testCase = getTestCase(testCase.getFullyQualifiedName(), queryParams, ADMIN_AUTH_HEADERS); assertEquals(testCaseResult, testCase.getTestCaseResult()); @@ -377,7 +376,7 @@ void getTestCaseWithResult(TestInfo test) throws IOException, ParseException { new CreateTestCaseResult() .withResult("tested") .withTestCaseStatus(TestCaseStatus.Success) - .withTimestamp(TestUtils.dateToTimestamp(String.format("2021-09-21"))); + .withTimestamp(TestUtils.dateToTimestamp("2021-09-21")); TestCaseResult futureTestCaseResult = postTestCaseResult( testCase.getFullyQualifiedName(), createTestCaseResult, ADMIN_AUTH_HEADERS); @@ -687,7 +686,7 @@ void test_getSimpleListFromSearch(TestInfo testInfo) throws IOException, ParseEx testSuiteResourceTest.addTestCasesToLogicalTestSuite( logicalTestSuite, List.of(testCaseForEL.getId())); - Map queryParams = new HashMap<>(); + Map queryParams = new HashMap<>(); ResultList allEntities = listEntitiesFromSearch(queryParams, testCasesNum, 0, ADMIN_AUTH_HEADERS); assertEquals(testCasesNum, allEntities.getData().size()); @@ -699,20 +698,20 @@ void test_getSimpleListFromSearch(TestInfo testInfo) throws IOException, ParseEx queryParams.clear(); queryParams.put("entityLink", testCaseForEL.getEntityLink()); - queryParams.put("includeAllTests", true); + queryParams.put("includeAllTests", "true"); allEntities = listEntitiesFromSearch(queryParams, testCasesNum, 0, ADMIN_AUTH_HEADERS); assertEquals(1, allEntities.getData().size()); org.assertj.core.api.Assertions.assertThat(allEntities.getData().get(0).getEntityLink()) .contains(testCaseForEL.getEntityLink()); queryParams.clear(); - queryParams.put("testPlatforms", TestPlatform.DEEQU); + queryParams.put("testPlatforms", TestPlatform.DEEQU.value()); allEntities = listEntitiesFromSearch(queryParams, testCasesNum, 0, ADMIN_AUTH_HEADERS); assertEquals( 0, allEntities.getData().size()); // we don't have any test cases with DEEQU platform queryParams.clear(); - queryParams.put("testPlatforms", TestPlatform.OPEN_METADATA); + queryParams.put("testPlatforms", TestPlatform.OPEN_METADATA.value()); allEntities = listEntitiesFromSearch(queryParams, testCasesNum, 0, ADMIN_AUTH_HEADERS); assertEquals( testCasesNum, @@ -814,7 +813,7 @@ void test_getSimpleListFromSearch(TestInfo testInfo) throws IOException, ParseEx // Test return only the specified test suite ID (Executable) queryParams.clear(); TestSuite testSuite = testSuites.get(tables.get(0).getFullyQualifiedName()); - queryParams.put("testSuiteId", testSuite.getId()); + queryParams.put("testSuiteId", testSuite.getId().toString()); queryParams.put("fields", "testSuites"); allEntities = listEntitiesFromSearch(queryParams, testCasesNum, 0, ADMIN_AUTH_HEADERS); testCases = allEntities.getData(); @@ -827,7 +826,7 @@ void test_getSimpleListFromSearch(TestInfo testInfo) throws IOException, ParseEx .anyMatch(ts -> ts.getId().equals(testSuite.getId())))); // Test return only the specified test suite ID (Logical) - queryParams.put("testSuiteId", logicalTestSuite.getId()); + queryParams.put("testSuiteId", logicalTestSuite.getId().toString()); queryParams.put("fields", "testSuites"); allEntities = listEntitiesFromSearch(queryParams, testCasesNum, 0, ADMIN_AUTH_HEADERS); testCases = allEntities.getData(); @@ -1169,6 +1168,20 @@ void post_createTestCaseResultFailure(TestInfo test) getTestCaseFailureStatus(startTs, endTs, null, null); assertEquals(4, testCaseFailureStatusResultList.getData().size()); + List ackStatuses = + testCaseFailureStatusResultList.getData().stream() + .filter( + status -> + status + .getTestCaseResolutionStatusType() + .equals(TestCaseResolutionStatusTypes.Ack)) + .toList(); + + ackStatuses.stream() + .flatMap(status -> status.getMetrics().stream()) + .filter(metric -> metric.getName().equals("timeToResponse")) + .forEach(metric -> assertNotNull(metric.getValue())); + // check we have only 2 distinct sequence IDs, one for each test case List stateIds = testCaseFailureStatusResultList.getData().stream() @@ -1472,6 +1485,9 @@ void test_testCaseResolutionTaskCloseWorkflowThruFeed(TestInfo test) mostRecentTestCaseResolutionStatusData.getTestCaseResolutionStatusType()); assertEquals( assignedIncident.getStateId(), mostRecentTestCaseResolutionStatusData.getStateId()); + mostRecentTestCaseResolutionStatusData.getMetrics().stream() + .filter(m -> m.getName().equals("timeToResolution")) + .forEach(m -> assertNotNull(m.getValue())); } @Test @@ -2523,9 +2539,8 @@ protected void validateListTestCaseResultsFromSearchWithPagination( assertEquals(offset, 0); } else { // Make sure scrolling back based on offset - limit cursor returns the correct result - backwardPage = - listTestCaseResultsFromSearch( - queryParams, limit, (offset - limit), path, ADMIN_AUTH_HEADERS); + listTestCaseResultsFromSearch( + queryParams, limit, (offset - limit), path, ADMIN_AUTH_HEADERS); assertEntityPagination(allEntities.getData(), forwardPage, limit, offset); } offset = offset + limit; @@ -2558,13 +2573,6 @@ protected void validateListTestCaseResultsFromSearchWithPagination( } } - public void putTestCaseResult(String fqn, TestCaseResult data, Map authHeaders) - throws HttpResponseException { - data.setTestCaseFQN(fqn); - WebTarget target = getResource(testCaseResultsCollectionName).path("/" + fqn); - TestUtils.put(target, data, CREATED, authHeaders); - } - public TestCaseResult postTestCaseResult( String fqn, CreateTestCaseResult data, Map authHeaders) throws HttpResponseException { @@ -3082,7 +3090,7 @@ void aggregate_testCaseResults(TestInfo testInfo) throws IOException, ParseExcep } @Test - void createTestCaseResults_wrongTs(TestInfo testInfo) throws IOException, HttpResponseException { + void createTestCaseResults_wrongTs(TestInfo testInfo) throws IOException { CreateTestCase create = createRequest(testInfo); TestCase testCase = createAndCheckEntity(create, ADMIN_AUTH_HEADERS); CreateTestCaseResult createTestCaseResult = @@ -3146,10 +3154,7 @@ void test_listTestCaseFromSearch(TestInfo testInfo) throws HttpResponseException assertNotEquals(testCaseResultResultList.getData().size(), 0); testCaseResultResultList .getData() - .forEach( - testCaseResult -> { - assertEquals(testCaseResult.getTimestamp(), ts); - }); + .forEach(testCaseResult -> assertEquals(testCaseResult.getTimestamp(), ts)); queryParams.clear(); queryParams.put("dataQualityDimension", "Completeness"); @@ -3178,7 +3183,6 @@ void test_listTestCaseFromSearch(TestInfo testInfo) throws HttpResponseException .getData() .forEach( testCaseResult -> { - EntityReference testDefinition = testCaseResult.getTestCase(); TestCase tc = Entity.getEntity(TEST_CASE, testCase.getId(), "", Include.ALL); assertTrue(tc.getEntityLink().contains("columns")); }); diff --git a/openmetadata-spec/src/main/resources/json/schema/tests/testCaseResolutionStatus.json b/openmetadata-spec/src/main/resources/json/schema/tests/testCaseResolutionStatus.json index 15121abb1176..e3e929861f41 100644 --- a/openmetadata-spec/src/main/resources/json/schema/tests/testCaseResolutionStatus.json +++ b/openmetadata-spec/src/main/resources/json/schema/tests/testCaseResolutionStatus.json @@ -31,6 +31,20 @@ {"name": "Severity4"}, {"name": "Severity5"} ] + }, + "metric": { + "description": "Representation of a metric.", + "javaType": "org.openmetadata.schema.tests.type.Metric", + "properties": { + "name": { + "description": "Name of the metric.", + "type": "string" + }, + "value": { + "description": "Value of the metric.", + "type": "number" + } + } } }, "properties": { @@ -74,6 +88,13 @@ "severity": { "description": "Severity failure for the test associated with the resolution.", "$ref": "#/definitions/severities" + }, + "metrics": { + "description": "List of metrics associated with the test case resolution.", + "type": "array", + "items": { + "$ref": "#/definitions/metric" + } } }, "required": ["testCaseResolutionStatusType"],