* fix(alerts): guard isBot() against deleted users to avoid aborting batches AlertsRuleEvaluator.isBot() called Entity.getEntityByName with Include.NON_DELETED without catching EntityNotFoundException. When a change event's userName referenced a user that had been deleted (common for short-lived test fixtures torn down by afterAll), the exception escaped the SpEL filter and was caught in AbstractEventConsumer.execute as "Error in polling events for alert : Entity not found: user ...". That outer catch logs the error and lets the finally block advance the offset by batchSize, silently dropping every other event in the batch. The ActivityFeedAlert subscription was hit hardest because every event flows through its isBot() filter rule. Catch EntityNotFoundException and treat an unresolvable actor as not-a-bot. * fix(alerts): null-safe getIsBot() + IT + unblock ActivityAPI spec - AlertsRuleEvaluator.isBot(): use Boolean.TRUE.equals(user.getIsBot()) so a null isBot field on the resolved user doesn't NPE on auto-unbox. - Add AlertsRuleEvaluatorResourceIT#test_isBot_returnsFalseWhenActorUserDeleted covering the original bug — create a user, evaluate isBot() (false), delete the user, evaluate isBot() again and assert it still returns false instead of throwing. - Remove test.describe.fixme from ActivityAPI.spec.ts so the spec runs again now that the underlying batch-abort is fixed. --------- Co-authored-by: Siddhant <siddhant@MacBook-Pro-751.local> |
||
|---|---|---|
| .. | ||
| 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.