From ece03712f89f00c268bb8e82dc9c0b2926c6a8a8 Mon Sep 17 00:00:00 2001 From: sureshms Date: Wed, 24 Nov 2021 06:36:40 -0800 Subject: [PATCH] Fixes #1358 - Add change events to DashboardService entity --- .../jdbi3/DashboardServiceRepository.java | 3 + .../dashboard/DashboardServiceResource.java | 55 ++++++- .../DashboardServiceResourceTest.java | 153 +++++++++--------- 3 files changed, 128 insertions(+), 83 deletions(-) diff --git a/catalog-rest-service/src/main/java/org/openmetadata/catalog/jdbi3/DashboardServiceRepository.java b/catalog-rest-service/src/main/java/org/openmetadata/catalog/jdbi3/DashboardServiceRepository.java index b64b0a6eccc..e9641a93e19 100644 --- a/catalog-rest-service/src/main/java/org/openmetadata/catalog/jdbi3/DashboardServiceRepository.java +++ b/catalog-rest-service/src/main/java/org/openmetadata/catalog/jdbi3/DashboardServiceRepository.java @@ -214,6 +214,9 @@ public class DashboardServiceRepository extends EntityRepository { - public DashboardServiceList(List data) { - super(data); + @SuppressWarnings("unused") /* Required for tests */ + public DashboardServiceList() {} + + public DashboardServiceList(List data, String beforeCursor, String afterCursor, int total) + throws GeneralSecurityException, UnsupportedEncodingException { + super(data, beforeCursor, afterCursor, total); } } @@ -106,13 +112,11 @@ public class DashboardServiceResource { throws IOException, GeneralSecurityException, ParseException { RestUtil.validateCursors(before, after); - ResultList list; if (before != null) { // Reverse paging - list = dao.listBefore(uriInfo, null, null, limitParam, before); - } else { // Forward paging or first page - list = dao.listAfter(uriInfo, null, null, limitParam, after); + return dao.listBefore(uriInfo, null, null, limitParam, before); } - return list; + // Forward paging + return dao.listAfter(uriInfo, null, null, limitParam, after); } @GET @@ -147,6 +151,43 @@ public class DashboardServiceResource { return dao.getByName(uriInfo, name, null); } + @GET + @Path("/{id}/versions") + @Operation(summary = "List dashboard service versions", tags = "services", + description = "Get a list of all the versions of a dashboard service identified by `id`", + responses = {@ApiResponse(responseCode = "200", description = "List of dashboard service versions", + content = @Content(mediaType = "application/json", + schema = @Schema(implementation = EntityHistory.class))) + }) + public EntityHistory listVersions(@Context UriInfo uriInfo, + @Context SecurityContext securityContext, + @Parameter(description = "dashboard service Id", schema = @Schema(type = "string")) + @PathParam("id") String id) + throws IOException, ParseException, GeneralSecurityException { + return dao.listVersions(id); + } + + @GET + @Path("/{id}/versions/{version}") + @Operation(summary = "Get a version of the dashboard service", tags = "services", + description = "Get a version of the dashboard service by given `id`", + responses = { + @ApiResponse(responseCode = "200", description = "dashboard service", + content = @Content(mediaType = "application/json", + schema = @Schema(implementation = DashboardService.class))), + @ApiResponse(responseCode = "404", description = "Dashboard service for instance {id} and version " + + "{version} is not found") + }) + public DashboardService getVersion(@Context UriInfo uriInfo, + @Context SecurityContext securityContext, + @Parameter(description = "dashboard service Id", schema = @Schema(type = "string")) + @PathParam("id") String id, + @Parameter(description = "dashboard service version number in the form `major`" + + ".`minor`", + schema = @Schema(type = "string", example = "0.1 or 1.1")) + @PathParam("version") String version) throws IOException, ParseException { + return dao.getVersion(id, version); + } @POST @Operation(summary = "Create a dashboard service", tags = "services", description = "Create a new dashboard service.", diff --git a/catalog-rest-service/src/test/java/org/openmetadata/catalog/resources/services/DashboardServiceResourceTest.java b/catalog-rest-service/src/test/java/org/openmetadata/catalog/resources/services/DashboardServiceResourceTest.java index 822674f027b..4dd0cc85751 100644 --- a/catalog-rest-service/src/test/java/org/openmetadata/catalog/resources/services/DashboardServiceResourceTest.java +++ b/catalog-rest-service/src/test/java/org/openmetadata/catalog/resources/services/DashboardServiceResourceTest.java @@ -25,11 +25,19 @@ import org.openmetadata.catalog.api.services.CreateDashboardService; import org.openmetadata.catalog.api.services.CreateDashboardService.DashboardServiceType; import org.openmetadata.catalog.entity.services.DashboardService; import org.openmetadata.catalog.exception.CatalogExceptionMessage; +import org.openmetadata.catalog.jdbi3.DashboardServiceRepository.DashboardServiceEntityInterface; +import org.openmetadata.catalog.resources.EntityResourceTest; +import org.openmetadata.catalog.resources.services.dashboard.DashboardServiceResource.DashboardServiceList; +import org.openmetadata.catalog.type.ChangeDescription; +import org.openmetadata.catalog.type.EntityReference; +import org.openmetadata.catalog.type.FieldChange; import org.openmetadata.catalog.type.Schedule; +import org.openmetadata.catalog.util.EntityInterface; import org.openmetadata.catalog.util.TestUtils; +import org.openmetadata.catalog.util.TestUtils.UpdateType; import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Response.Status; +import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Date; @@ -41,13 +49,17 @@ import static javax.ws.rs.core.Response.Status.CONFLICT; 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; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.openmetadata.catalog.util.TestUtils.adminAuthHeaders; import static org.openmetadata.catalog.util.TestUtils.authHeaders; -public class DashboardServiceResourceTest extends CatalogApplicationTest { +public class DashboardServiceResourceTest extends EntityResourceTest { + public DashboardServiceResourceTest() { + super(Entity.DASHBOARD_SERVICE, DashboardService.class, DashboardServiceList.class, "services/dashboardServices", + "", false, false, false); + this.supportsPatch = false; + } + @Test public void post_serviceWithLongName_400_badRequest(TestInfo test) throws URISyntaxException { // Create dashboard with mandatory name field empty @@ -90,12 +102,12 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest { } @Test - public void post_validService_as_admin_200_ok(TestInfo test) throws HttpResponseException, URISyntaxException { + public void post_validService_as_admin_200_ok(TestInfo test) throws IOException, URISyntaxException { // Create dashboard service with different optional fields Map authHeaders = adminAuthHeaders(); - createAndCheckService(create(test, 1).withDescription(null), authHeaders); - createAndCheckService(create(test, 2).withDescription("description"), authHeaders); - createAndCheckService(create(test, 3).withIngestionSchedule(null), authHeaders); + createAndCheckEntity(create(test, 1).withDescription(null), authHeaders); + createAndCheckEntity(create(test, 2).withDescription("description"), authHeaders); + createAndCheckEntity(create(test, 3).withIngestionSchedule(null), authHeaders); } @Test @@ -104,7 +116,7 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest { Map authHeaders = authHeaders("test@open-metadata.org"); HttpResponseException exception = assertThrows(HttpResponseException.class, () -> - createAndCheckService(create(test, 1).withDescription(null), authHeaders)); + createAndCheckEntity(create(test, 1).withDescription(null), authHeaders)); TestUtils.assertResponse(exception, FORBIDDEN, "Principal: CatalogPrincipal{name='test'} is not admin"); } @@ -143,16 +155,16 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest { @Test public void post_validIngestionSchedules_as_admin_200(TestInfo test) - throws HttpResponseException, URISyntaxException { + throws IOException, URISyntaxException { Schedule schedule = new Schedule().withStartDate(new Date()); schedule.withRepeatFrequency("PT60M"); // Repeat every 60M should be valid - createAndCheckService(create(test, 1).withIngestionSchedule(schedule), adminAuthHeaders()); + createAndCheckEntity(create(test, 1).withIngestionSchedule(schedule), adminAuthHeaders()); schedule.withRepeatFrequency("PT1H49M"); - createAndCheckService(create(test, 2).withIngestionSchedule(schedule), adminAuthHeaders()); + createAndCheckEntity(create(test, 2).withIngestionSchedule(schedule), adminAuthHeaders()); schedule.withRepeatFrequency("P1DT1H49M"); - createAndCheckService(create(test, 3).withIngestionSchedule(schedule), adminAuthHeaders()); + createAndCheckEntity(create(test, 3).withIngestionSchedule(schedule), adminAuthHeaders()); } @Test @@ -173,34 +185,42 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest { } @Test - public void put_updateService_as_admin_2xx(TestInfo test) throws HttpResponseException, URISyntaxException { - DashboardService dbService = createAndCheckService(create(test).withDescription(null).withIngestionSchedule(null), + public void put_updateService_as_admin_2xx(TestInfo test) throws IOException, URISyntaxException { + DashboardService service = createAndCheckEntity(create(test).withDescription(null).withIngestionSchedule(null), adminAuthHeaders()); // Update dashboard description and ingestion service that are null + Schedule schedule = new Schedule().withStartDate(new Date()).withRepeatFrequency("P1D"); CreateDashboardService update = create(test).withDescription("description1") - .withDashboardUrl(new URI("http://localhost:8080")).withUsername("user").withPassword("password"); - updateAndCheckService(update, OK, adminAuthHeaders()); + .withDashboardUrl(new URI("http://localhost:8080")).withUsername("user").withPassword("password") + .withIngestionSchedule(schedule); + + ChangeDescription change = getChangeDescription(service.getVersion()); + change.getFieldsAdded().add(new FieldChange().withName("description").withNewValue("description1")); + change.getFieldsAdded().add(new FieldChange().withName("userName").withNewValue("user")); + change.getFieldsAdded().add(new FieldChange().withName("ingestionSchedule").withNewValue("password")); + change.getFieldsUpdated().add(new FieldChange().withName("dashboardUrl").withOldValue("http://192.1.1.1:0") + .withNewValue("http://localhost:8080")); + service = updateAndCheckEntity(update, OK, adminAuthHeaders(), UpdateType.MINOR_UPDATE, change); // Update ingestion schedule - Schedule schedule = new Schedule().withStartDate(new Date()).withRepeatFrequency("P1D"); - update.withIngestionSchedule(schedule); - updateAndCheckService(update, OK, adminAuthHeaders()); - - // Update description and ingestion schedule again - update.withDescription("description1").withIngestionSchedule(schedule.withRepeatFrequency("PT1H")); - updateAndCheckService(update, OK, adminAuthHeaders()); + Schedule schedule1 = new Schedule().withStartDate(new Date()).withRepeatFrequency("PT1H"); + change = getChangeDescription(service.getVersion()); + change.getFieldsUpdated().add(new FieldChange().withName("ingestionSchedule").withOldValue(schedule) + .withNewValue(schedule1)); + update.withIngestionSchedule(schedule1); + updateAndCheckEntity(update, OK, adminAuthHeaders(), UpdateType.MINOR_UPDATE, change); } @Test - public void put_update_as_non_admin_401(TestInfo test) throws HttpResponseException, URISyntaxException { + public void put_update_as_non_admin_401(TestInfo test) throws IOException, URISyntaxException { Map authHeaders = adminAuthHeaders(); - DashboardService dbService = createAndCheckService(create(test).withDescription(null).withIngestionSchedule(null), - authHeaders); + createAndCheckEntity(create(test).withDescription(null).withIngestionSchedule(null), authHeaders); // Update dashboard description and ingestion service that are null HttpResponseException exception = assertThrows(HttpResponseException.class, () -> - updateAndCheckService(create(test), OK, authHeaders("test@open-metadata.org"))); + updateAndCheckEntity(create(test), OK, authHeaders("test@open-metadata.org"), + UpdateType.NO_CHANGE, null)); TestUtils.assertResponse(exception, FORBIDDEN, "Principal: CatalogPrincipal{name='test'} " + "is not admin"); } @@ -221,43 +241,12 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest { "invalidName")); } - public static DashboardService createAndCheckService(CreateDashboardService create, - Map authHeaders) throws HttpResponseException { - String updatedBy = TestUtils.getPrincipal(authHeaders); - DashboardService service = createService(create, authHeaders); - validateService(service, create.getName(), create.getDescription(), create.getIngestionSchedule(), updatedBy); - assertEquals(0.1, service.getVersion()); - - // GET the newly created service and validate - DashboardService getService = getService(service.getId(), authHeaders); - validateService(getService, create.getName(), create.getDescription(), create.getIngestionSchedule(), updatedBy); - - // GET the newly created service by name and validate - getService = getServiceByName(service.getName(), null, authHeaders); - validateService(getService, create.getName(), create.getDescription(), create.getIngestionSchedule(), updatedBy); - return service; - } - public static DashboardService createService(CreateDashboardService create, Map authHeaders) throws HttpResponseException { return TestUtils.post(CatalogApplicationTest.getResource("services/dashboardServices"), create, DashboardService.class, authHeaders); } - private static void validateService(DashboardService service, String expectedName, String expectedDescription, - Schedule expectedIngestion, String expectedUpdatedBy) { - assertNotNull(service.getId()); - assertNotNull(service.getHref()); - assertEquals(expectedName, service.getName()); - assertEquals(expectedDescription, service.getDescription()); - assertEquals(expectedUpdatedBy, service.getUpdatedBy()); - - if (expectedIngestion != null) { - assertEquals(expectedIngestion.getStartDate(), service.getIngestionSchedule().getStartDate()); - assertEquals(expectedIngestion.getRepeatFrequency(), service.getIngestionSchedule().getRepeatFrequency()); - } - } - public static DashboardService getService(UUID id, Map authHeaders) throws HttpResponseException { return getService(id, null, authHeaders); } @@ -338,25 +327,37 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest { .withIngestionSchedule(new Schedule().withStartDate(new Date()).withRepeatFrequency("P1D")); } - public static void updateAndCheckService(CreateDashboardService update, Status status, - Map authHeaders) throws HttpResponseException { - String updatedBy = TestUtils.getPrincipal(authHeaders); - DashboardService service = updateDashboardService(update, status, authHeaders); - validateService(service, service.getName(), update.getDescription(), update.getIngestionSchedule(), updatedBy); - - // GET the newly updated dashboard and validate - DashboardService getService = getService(service.getId(), authHeaders); - validateService(getService, service.getName(), update.getDescription(), update.getIngestionSchedule(), updatedBy); - - // GET the newly updated dashboard by name and validate - getService = getServiceByName(service.getName(), null, authHeaders); - validateService(getService, service.getName(), update.getDescription(), update.getIngestionSchedule(), updatedBy); + @Override + public Object createRequest(TestInfo test, int index, String description, String displayName, EntityReference owner) + throws URISyntaxException { + return create(test, index).withDescription(description).withIngestionSchedule(null); } - public static DashboardService updateDashboardService(CreateDashboardService updated, - Status status, Map authHeaders) + @Override + public void validateCreatedEntity(DashboardService createdEntity, Object request, Map authHeaders) throws HttpResponseException { - return TestUtils.put(CatalogApplicationTest.getResource("services/dashboardServices"), updated, - DashboardService.class, status, authHeaders); + + } + + @Override + public void validateUpdatedEntity(DashboardService updatedEntity, Object request, Map authHeaders) + throws HttpResponseException { + + } + + @Override + public void compareEntities(DashboardService expected, DashboardService updated, Map authHeaders) + throws HttpResponseException { + + } + + @Override + public EntityInterface getEntityInterface(DashboardService entity) { + return new DashboardServiceEntityInterface(entity); + } + + @Override + public void assertFieldChange(String fieldName, Object expected, Object actual) throws IOException { + } }