* Add changeSummary API endpoint and UI components for description source tracking
Add a new /v1/changeSummary/{entityType}/{id|name/fqn} endpoint that
returns per-field change metadata (who changed it, source type, timestamp).
Supports fieldPrefix filtering for column-level queries on large tables
and limit/offset pagination.
UI additions:
- DescriptionSourceBadge component showing AI badge on AI-generated descriptions
- useChangeSummary hook for fetching change summary data
- changeSummaryAPI REST client
- "accepted-by" translation key
Integration tests added to BaseEntityIT covering all entity types:
get by ID, get by FQN, fieldPrefix filtering, pagination, and 404 cases.
Closes #1648
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix checkstyle
* Integrate DescriptionSourceBadge into UI and address PR review comments
- Add authorization checks (VIEW_BASIC) to ChangeSummaryResource endpoints
- Fix pagination defaults and simplify pagination logic
- Remove silent try-catch in integration tests, use assertThrows for 404
- Wire useChangeSummary hook into GenericProvider context
- Render AI-generated badge on entity descriptions (DescriptionV1)
- Render AI-generated badge on column descriptions (TableDescription)
- Pass changeSummary entry to ColumnDetailPanel's DescriptionSection
- Fix stale useMemo dependency in DescriptionV1 header
- Fix missing Less variable import in description-source-badge.less
- Add Playwright E2E tests for ChangeSummary badge feature
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Address PR review feedback: fix column FQN parsing, badge labels, backend optimization
- Fix ColumnDetailPanel to use EntityLink.getTableColumnNameFromColumnFqn
instead of naive substring for changeSummary key lookup
- Show correct badge label per source type (AI/Automated/Propagated)
instead of always showing "Automated"
- Fetch only changeDescription field instead of * in both endpoints
- Add @Min/@Max validation for limit and offset parameters
- Pass uriInfo to repository calls instead of null
- Pass explicit limit=1000 in GenericProvider to avoid truncated results
- Import ChangeSource from generated/type/changeSummaryMap (correct schema)
- Add getChangeSummaryByFqn to REST client matching API surface
- Add keyboard accessibility (tabIndex, role) to badge
- Remove untranslated "accepted-by" from non-English locales (fallback to en-us)
- Add "ai" label key to en-us locale
- Strengthen integration test assertions to verify non-empty results
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Improve change summary description layout
* Expand change summary support across assets
* Fix changeSummary race condition and LLMModel entity type mismatch
- Add request cancellation to useChangeSummary hook to prevent stale data
when users switch entities rapidly
- Fix LLMModelResourceIT entity type from "llmmodel" to "llmModel" to match
the registered entity type in Entity.java
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix Playwright strict mode violation and sync i18n translations
- Use .first() for ai-suggested-badge locator in ChangeSummaryBadge test
to handle DescriptionV1 rendering the badge in both header and metadata
- Reorder imports per organize-imports rules
- Sync ai-suggested and authored-by keys to all 18 locale files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix
* fix
* fix
* implemented the new UI changes for AI description
* fixed the lint issues
* addressed gitar comment
* fixed the translations
* fixed unit test
* addressed PR comment
* fixed odcs playwright test
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Pere Miquel Brull <peremiquelbrull@gmail.com>
Co-authored-by: Rohit0301 <rj03012002@gmail.com>
Co-authored-by: Rohit Jain <60229265+Rohit0301@users.noreply.github.com>
|
||
|---|---|---|
| .. | ||
| src/test | ||
| K8S_TESTS.md | ||
| pom.xml | ||
| README.md | ||
| TEST_MIGRATION_TRACKER.md | ||
OpenMetadata Integration Tests
This module contains SDK-based integration tests that run against a real OpenMetadata server using Testcontainers. Tests execute in parallel and are isolated using TestNamespace.
Quick Start
# Run all tests with MySQL + Elasticsearch (default)
mvn test -pl :openmetadata-integration-tests
# Run with PostgreSQL + OpenSearch
mvn test -pl :openmetadata-integration-tests -Ppostgres-opensearch
# Run a specific test
mvn test -pl :openmetadata-integration-tests -Dtest="TableResourceIT"
Available Profiles
| Profile | Database | Search Engine |
|---|---|---|
mysql-elasticsearch (default) |
MySQL 8.3.0 | Elasticsearch 8.11.4 |
postgres-opensearch |
PostgreSQL 15 | OpenSearch 2.19.0 |
postgres-elasticsearch |
PostgreSQL 15 | Elasticsearch 8.11.4 |
mysql-opensearch |
MySQL 8.3.0 | OpenSearch 2.19.0 |
Writing a New Integration Test
1. Create the Test Class
Extend BaseEntityIT for entity CRUD tests or create a standalone test class:
package org.openmetadata.it.tests;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
import org.openmetadata.it.util.TestNamespace;
import org.openmetadata.schema.api.data.CreateTable;
import org.openmetadata.schema.entity.data.Table;
public class MyFeatureIT extends BaseEntityIT<Table, CreateTable> {
@Override
protected String getEntityType() {
return "table";
}
@Override
protected Table createEntity(CreateTable request) {
return SdkClients.adminClient().tables().create(request);
}
@Override
protected CreateTable createRequest(String name, TestNamespace ns) {
return new CreateTable()
.withName(name)
.withDatabaseSchema(SharedEntities.getSchema().getFullyQualifiedName())
.withColumns(List.of(new Column().withName("id").withDataType(ColumnDataType.INT)));
}
@Test
void myCustomTest(TestNamespace ns) throws Exception {
CreateTable request = createRequest(ns.prefix("myTable"), ns);
Table table = createEntity(request);
assertNotNull(table.getId());
assertEquals(request.getName(), table.getName());
}
}
2. Key Concepts
TestNamespace
Every test method receives a TestNamespace parameter that provides unique prefixes for entity names:
@Test
void myTest(TestNamespace ns) {
String uniqueName = ns.prefix("myEntity"); // e.g., "abc123_myEntity"
}
This ensures tests don't conflict when running in parallel.
SdkClients
Get pre-configured SDK clients for different users:
OpenMetadataClient adminClient = SdkClients.adminClient();
OpenMetadataClient user1Client = SdkClients.user1Client();
OpenMetadataClient botClient = SdkClients.botClient();
SharedEntities
Access pre-created entities for tests:
DatabaseService service = SharedEntities.getService();
Database database = SharedEntities.getDatabase();
DatabaseSchema schema = SharedEntities.getSchema();
User adminUser = SharedEntities.getAdminUser();
3. BaseEntityIT Features
When extending BaseEntityIT, you get these tests automatically:
| Test | Description |
|---|---|
post_entityCreate_200 |
Create entity successfully |
get_entity_200_OK |
Get entity by ID |
get_entityByName_200 |
Get entity by FQN |
get_entityNotFound_404 |
Get non-existent entity |
put_entityCreate_200 |
Create via PUT |
patch_entityAttributes_200 |
Patch entity attributes |
delete_entityAsAdmin_200 |
Delete entity |
get_entityListWithPagination_200 |
List with pagination |
test_sdkCRUDOperations |
Full CRUD via SDK |
| ... and 30+ more |
4. Controlling Test Behavior
Use flags to customize which inherited tests run:
public class MyEntityIT extends BaseEntityIT<MyEntity, CreateMyEntity> {
{
supportsPatch = true; // Enable PATCH tests
supportsTags = true; // Enable tag tests
supportsOwner = true; // Enable owner tests
supportsSearchIndex = true; // Enable search tests
supportsDomains = true; // Enable domain tests
}
}
5. Best Practices
- Use
TestNamespace.prefix()for all entity names to ensure uniqueness - Don't clean up entities - TestNamespace isolation handles this
- Use specific imports - No wildcard imports (
import static ....*) - Keep tests independent - Don't rely on order of execution
- Use Awaitility for async operations - Not
Thread.sleep()
Awaitility.await()
.atMost(Duration.ofSeconds(30))
.pollInterval(Duration.ofMillis(500))
.until(() -> someCondition());
- Avoid single-line comments - Write self-documenting code
Project Structure
openmetadata-integration-tests/
├── src/test/java/org/openmetadata/it/
│ ├── auth/ # JWT token generation
│ ├── env/ # Test infrastructure (TestSuiteBootstrap)
│ ├── factories/ # Entity factory classes
│ ├── tests/ # Integration test classes
│ └── util/ # Utilities (SdkClients, TestNamespace)
└── src/test/resources/
├── openmetadata-secure-test.yaml # Test config
└── *.der # JWT keys
Test Infrastructure
Tests use TestSuiteBootstrap (a JUnit LauncherSessionListener) that:
- Starts database container (MySQL or PostgreSQL)
- Starts search container (Elasticsearch or OpenSearch)
- Starts Fuseki SPARQL container (for RDF tests)
- Starts the OpenMetadata application
- Initializes
SharedEntities
All containers are started once per test run and shared across all tests.
Running in CI
GitHub workflows run these tests on every PR:
integration-tests-mysql-elasticsearch.yml- MySQL + Elasticsearchintegration-tests-postgres-opensearch.yml- PostgreSQL + OpenSearch
Tests require the "safe to test" label on PRs.