From 2e1786f7b6377b7f4cbda356bd724652301f0abf Mon Sep 17 00:00:00 2001 From: Imri Paran Date: Mon, 22 Apr 2024 11:10:59 +0200 Subject: [PATCH] MINOR: use polling mechanism for bnackend tests (#15962) * handle unstable tests * handle retry by polling ES * remove waitForAsyncOp * use retry * format * poll elastic for 10 seconds * fixed tag delete test with polling * poll up to 3 seconds * fixed tag delete test again * fixed assertEntityReferenceFromSearch * fixed assertEntityReferenceFromSearch * better error messages --- .../service/resources/EntityResourceTest.java | 112 +++++++++++------- .../glossary/GlossaryTermResourceTest.java | 1 + .../service/util/RetryableAssertionError.java | 7 ++ .../openmetadata/service/util/TestUtils.java | 39 ++++++ 4 files changed, 117 insertions(+), 42 deletions(-) create mode 100644 openmetadata-service/src/test/java/org/openmetadata/service/util/RetryableAssertionError.java diff --git a/openmetadata-service/src/test/java/org/openmetadata/service/resources/EntityResourceTest.java b/openmetadata-service/src/test/java/org/openmetadata/service/resources/EntityResourceTest.java index 07a7f0aa2d4..9dd81c7ac13 100644 --- a/openmetadata-service/src/test/java/org/openmetadata/service/resources/EntityResourceTest.java +++ b/openmetadata-service/src/test/java/org/openmetadata/service/resources/EntityResourceTest.java @@ -2019,7 +2019,9 @@ public abstract class EntityResourceTest sourceAsMap = hit.getSourceAsMap(); - if (sourceAsMap.get("id").toString().equals(entity.getId().toString())) { - @SuppressWarnings("unchecked") - List> listTags = (List>) sourceAsMap.get("tags"); - listTags.forEach(tempMap -> fqnList.add(tempMap.get("tagFQN"))); - break; - } - } - // check if the relationships of tag are also deleted in search - assertFalse(fqnList.contains(tagLabel.getTagFQN())); + + T finalEntity = entity; + TestUtils.assertEventually( + test.getDisplayName(), + () -> { + fqnList.clear(); + SearchResponse afterDeleteResponse; + try { + afterDeleteResponse = + getResponseFormSearch( + indexMapping.getIndexName(Entity.getSearchRepository().getClusterAlias())); + } catch (HttpResponseException e) { + throw new RuntimeException(e); + } + + SearchHit[] hitsAfterDelete = afterDeleteResponse.getHits().getHits(); + for (SearchHit hit : hitsAfterDelete) { + Map sourceAsMap = hit.getSourceAsMap(); + if (sourceAsMap.get("id").toString().equals(finalEntity.getId().toString())) { + @SuppressWarnings("unchecked") + List> listTags = + (List>) sourceAsMap.get("tags"); + listTags.forEach(tempMap -> fqnList.add(tempMap.get("tagFQN"))); + break; + } + } + // check if the relationships of tag are also deleted in search + assertFalse(fqnList.contains(tagLabel.getTagFQN())); + }); } @Test @@ -2587,7 +2601,9 @@ public abstract class EntityResourceTest authHeaders) throws IOException { // Validate an entity that is created has all the information set in create request String updatedBy = SecurityUtil.getPrincipalName(authHeaders); @@ -2712,7 +2728,9 @@ public abstract class EntityResourceTest()); } - /** Compare fullyQualifiedName in the entityReference */ + /** + * Compare fullyQualifiedName in the entityReference + */ protected static void assertReference(String expected, EntityReference actual) { if (expected != null) { assertNotNull(actual); @@ -3128,7 +3148,9 @@ public abstract class EntityResourceTest { + Response response = searchClient.performRequest(request); + String jsonString = EntityUtils.toString(response.getEntity()); + @SuppressWarnings("unchecked") + HashMap map = + (HashMap) JsonUtils.readOrConvertValue(jsonString, HashMap.class); + @SuppressWarnings("unchecked") + LinkedHashMap hits = (LinkedHashMap) map.get("hits"); + @SuppressWarnings("unchecked") + ArrayList> hitsList = + (ArrayList>) hits.get("hits"); + assertEquals(1, hitsList.size()); + LinkedHashMap doc = hitsList.get(0); + @SuppressWarnings("unchecked") + LinkedHashMap source = + (LinkedHashMap) doc.get("_source"); + + EntityReference domainReference = + JsonUtils.readOrConvertValue(source.get("domain"), EntityReference.class); + + assertEquals(domainReference.getId(), actual.getId()); + assertEquals(domainReference.getType(), actual.getType()); + }); } finally { searchClient.close(); } - - String jsonString = EntityUtils.toString(response.getEntity()); - HashMap map = - (HashMap) JsonUtils.readOrConvertValue(jsonString, HashMap.class); - LinkedHashMap hits = (LinkedHashMap) map.get("hits"); - ArrayList> hitsList = - (ArrayList>) hits.get("hits"); - assertEquals(1, hitsList.size()); - LinkedHashMap doc = (LinkedHashMap) hitsList.get(0); - LinkedHashMap source = (LinkedHashMap) doc.get("_source"); - - EntityReference domainReference = - JsonUtils.readOrConvertValue(source.get("domain"), EntityReference.class); - - assertEquals(domainReference.getId(), actual.getId()); - assertEquals(domainReference.getType(), actual.getType()); } protected static void checkOwnerOwns(EntityReference owner, UUID entityId, boolean expectedOwning) diff --git a/openmetadata-service/src/test/java/org/openmetadata/service/resources/glossary/GlossaryTermResourceTest.java b/openmetadata-service/src/test/java/org/openmetadata/service/resources/glossary/GlossaryTermResourceTest.java index 47bf7be141d..7feaa91e438 100644 --- a/openmetadata-service/src/test/java/org/openmetadata/service/resources/glossary/GlossaryTermResourceTest.java +++ b/openmetadata-service/src/test/java/org/openmetadata/service/resources/glossary/GlossaryTermResourceTest.java @@ -215,6 +215,7 @@ public class GlossaryTermResourceTest extends EntityResourceTest expected, List actual) { if (expected == actual) { // Take care of both being null @@ -654,4 +668,29 @@ public final class TestUtils { // the owner of the async operation TimeUnit.MILLISECONDS.sleep(milliseconds); } + + public static void assertEventually(String name, CheckedRunnable runnable) { + try { + Retry.decorateCheckedRunnable( + elasticSearchRetryRegistry.retry(name), + () -> { + try { + runnable.run(); + } catch (AssertionError e) { + // translate AssertionErrors to Exceptions to that retry processes + // them correctly. This is required because retry library only retries on + // Exceptions and: + // AssertionError -> Error -> Throwable + // RetryableAssertionError -> Exception -> Throwable + throw new RetryableAssertionError(e); + } + }) + .run(); + } catch (RetryableAssertionError e) { + throw new AssertionFailedError( + "Max retries exceeded polling for eventual assert", e.getCause()); + } catch (Throwable e) { + throw new AssertionFailedError("Unexpected error while running retry: " + e.getMessage(), e); + } + } }