mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-11-04 04:29:13 +00:00 
			
		
		
		
	Merge pull request #1359 from open-metadata/issue1358
Fixes #1358 - Add change events to Service entity
This commit is contained in:
		
						commit
						9cd170c95b
					
				@ -214,6 +214,9 @@ public class DashboardServiceRepository extends EntityRepository<DashboardServic
 | 
			
		||||
    public void entitySpecificUpdate() throws IOException {
 | 
			
		||||
      updateDashboardUrl();
 | 
			
		||||
      updateIngestionSchedule();
 | 
			
		||||
      recordChange("userName", original.getEntity().getUsername(), updated.getEntity().getUsername());
 | 
			
		||||
      // TODO change recorded for password
 | 
			
		||||
//      recordChange("password", original.getEntity().getPassword(), updated.getEntity().getPassword());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateDashboardUrl() throws JsonProcessingException {
 | 
			
		||||
@ -223,7 +226,7 @@ public class DashboardServiceRepository extends EntityRepository<DashboardServic
 | 
			
		||||
    private void updateIngestionSchedule() throws JsonProcessingException {
 | 
			
		||||
      Schedule origSchedule = original.getEntity().getIngestionSchedule();
 | 
			
		||||
      Schedule updatedSchedule = updated.getEntity().getIngestionSchedule();
 | 
			
		||||
      recordChange("ingestionSchedule", origSchedule, updatedSchedule);
 | 
			
		||||
      recordChange("ingestionSchedule", origSchedule, updatedSchedule, true);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -32,7 +32,6 @@ import org.openmetadata.catalog.util.EntityUtil;
 | 
			
		||||
import org.openmetadata.catalog.util.EntityUtil.Fields;
 | 
			
		||||
import org.openmetadata.catalog.util.JsonUtils;
 | 
			
		||||
 | 
			
		||||
import javax.ws.rs.core.UriInfo;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
import java.text.ParseException;
 | 
			
		||||
@ -213,7 +212,7 @@ public class DatabaseServiceRepository extends EntityRepository<DatabaseService>
 | 
			
		||||
    private void updateIngestionSchedule() throws JsonProcessingException {
 | 
			
		||||
      Schedule origSchedule = original.getEntity().getIngestionSchedule();
 | 
			
		||||
      Schedule updatedSchedule = updated.getEntity().getIngestionSchedule();
 | 
			
		||||
      recordChange("ingestionSchedule", origSchedule, updatedSchedule);
 | 
			
		||||
      recordChange("ingestionSchedule", origSchedule, updatedSchedule, true);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -34,6 +34,7 @@ import org.openmetadata.catalog.util.JsonUtils;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
import java.text.ParseException;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
@ -199,6 +200,7 @@ public class MessagingServiceRepository extends EntityRepository<MessagingServic
 | 
			
		||||
    public void entitySpecificUpdate() throws IOException {
 | 
			
		||||
      updateSchemaRegistry();
 | 
			
		||||
      updateIngestionSchedule();
 | 
			
		||||
      updateBrokers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateSchemaRegistry() throws JsonProcessingException {
 | 
			
		||||
@ -208,7 +210,16 @@ public class MessagingServiceRepository extends EntityRepository<MessagingServic
 | 
			
		||||
    private void updateIngestionSchedule() throws JsonProcessingException {
 | 
			
		||||
      Schedule origSchedule = original.getEntity().getIngestionSchedule();
 | 
			
		||||
      Schedule updatedSchedule = updated.getEntity().getIngestionSchedule();
 | 
			
		||||
      recordChange("ingestionSchedule", origSchedule, updatedSchedule);
 | 
			
		||||
      recordChange("ingestionSchedule", origSchedule, updatedSchedule, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateBrokers() throws JsonProcessingException {
 | 
			
		||||
      List<String> origBrokers = original.getEntity().getBrokers();
 | 
			
		||||
      List<String> updatedBrokers = updated.getEntity().getBrokers();
 | 
			
		||||
 | 
			
		||||
      List<String> addedBrokers = new ArrayList<>();
 | 
			
		||||
      List<String> deletedBrokers = new ArrayList<>();
 | 
			
		||||
      recordListChange("brokers", origBrokers, updatedBrokers, addedBrokers, deletedBrokers, EntityUtil.stringMatch);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -201,18 +201,14 @@ public class PipelineServiceRepository extends EntityRepository<PipelineService>
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void entitySpecificUpdate() throws IOException {
 | 
			
		||||
      updatePipelineUrl();
 | 
			
		||||
      updateIngestionSchedule();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updatePipelineUrl() throws JsonProcessingException {
 | 
			
		||||
      recordChange("pipelineUrl", original.getEntity().getPipelineUrl(), updated.getEntity().getPipelineUrl());
 | 
			
		||||
      updateIngestionSchedule();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateIngestionSchedule() throws JsonProcessingException {
 | 
			
		||||
      Schedule origSchedule = original.getEntity().getIngestionSchedule();
 | 
			
		||||
      Schedule updatedSchedule = updated.getEntity().getIngestionSchedule();
 | 
			
		||||
      recordChange("ingestionSchedule", origSchedule, updatedSchedule);
 | 
			
		||||
      recordChange("ingestionSchedule", origSchedule, updatedSchedule, true);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -30,6 +30,7 @@ import org.openmetadata.catalog.jdbi3.DashboardServiceRepository;
 | 
			
		||||
import org.openmetadata.catalog.resources.Collection;
 | 
			
		||||
import org.openmetadata.catalog.security.CatalogAuthorizer;
 | 
			
		||||
import org.openmetadata.catalog.security.SecurityUtil;
 | 
			
		||||
import org.openmetadata.catalog.type.EntityHistory;
 | 
			
		||||
import org.openmetadata.catalog.util.RestUtil;
 | 
			
		||||
import org.openmetadata.catalog.util.RestUtil.PutResponse;
 | 
			
		||||
import org.openmetadata.catalog.util.ResultList;
 | 
			
		||||
@ -53,6 +54,7 @@ import javax.ws.rs.core.Response;
 | 
			
		||||
import javax.ws.rs.core.SecurityContext;
 | 
			
		||||
import javax.ws.rs.core.UriInfo;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.UnsupportedEncodingException;
 | 
			
		||||
import java.security.GeneralSecurityException;
 | 
			
		||||
import java.text.ParseException;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
@ -78,8 +80,12 @@ public class DashboardServiceResource {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static class DashboardServiceList extends ResultList<DashboardService> {
 | 
			
		||||
    public DashboardServiceList(List<DashboardService> data) {
 | 
			
		||||
      super(data);
 | 
			
		||||
    @SuppressWarnings("unused") /* Required for tests */
 | 
			
		||||
    public DashboardServiceList() {}
 | 
			
		||||
 | 
			
		||||
    public DashboardServiceList(List<DashboardService> 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<DashboardService> 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.",
 | 
			
		||||
 | 
			
		||||
@ -91,6 +91,9 @@ public final class EntityUtil {
 | 
			
		||||
  public static BiPredicate<Task, Task> taskMatch = (task1, task2) ->
 | 
			
		||||
          task1.getName().equals(task2.getName());
 | 
			
		||||
 | 
			
		||||
  public static BiPredicate<String, String> stringMatch = (string1, string2) ->
 | 
			
		||||
          string1.equals(string2);
 | 
			
		||||
 | 
			
		||||
  public static BiPredicate<Column, Column> columnMatch = (column1, column2) ->
 | 
			
		||||
          column1.getName().equals(column2.getName()) &&
 | 
			
		||||
          column1.getDataType() == column2.getDataType() &&
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,7 @@ import org.openmetadata.catalog.resources.events.EventResource.ChangeEventList;
 | 
			
		||||
import org.openmetadata.catalog.resources.services.DatabaseServiceResourceTest;
 | 
			
		||||
import org.openmetadata.catalog.resources.services.MessagingServiceResourceTest;
 | 
			
		||||
import org.openmetadata.catalog.resources.tags.TagResourceTest;
 | 
			
		||||
import org.openmetadata.catalog.resources.services.PipelineServiceResourceTest;
 | 
			
		||||
import org.openmetadata.catalog.resources.teams.TeamResourceTest;
 | 
			
		||||
import org.openmetadata.catalog.resources.teams.UserResourceTest;
 | 
			
		||||
import org.openmetadata.catalog.type.ChangeDescription;
 | 
			
		||||
@ -70,7 +71,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertNull;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertThrows;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertTrue;
 | 
			
		||||
import static org.openmetadata.catalog.resources.services.PipelineServiceResourceTest.createService;
 | 
			
		||||
import static org.openmetadata.catalog.util.TestUtils.NON_EXISTENT_ENTITY;
 | 
			
		||||
import static org.openmetadata.catalog.util.TestUtils.UpdateType;
 | 
			
		||||
import static org.openmetadata.catalog.util.TestUtils.UpdateType.MINOR_UPDATE;
 | 
			
		||||
@ -138,45 +138,48 @@ public abstract class EntityResourceTest<T> extends CatalogApplicationTest {
 | 
			
		||||
    CreateDatabaseService createDatabaseService = new CreateDatabaseService()
 | 
			
		||||
            .withName(DatabaseServiceResourceTest.getName(test, 1))
 | 
			
		||||
            .withServiceType(DatabaseServiceType.Snowflake).withJdbc(TestUtils.JDBC_INFO);
 | 
			
		||||
    DatabaseService databaseService = DatabaseServiceResourceTest.createService(createDatabaseService,
 | 
			
		||||
    DatabaseService databaseService = new DatabaseServiceResourceTest().createEntity(createDatabaseService,
 | 
			
		||||
            adminAuthHeaders());
 | 
			
		||||
    SNOWFLAKE_REFERENCE = new EntityReference().withName(databaseService.getName()).withId(databaseService.getId())
 | 
			
		||||
            .withType(Entity.DATABASE_SERVICE);
 | 
			
		||||
 | 
			
		||||
    DatabaseServiceResourceTest databaseServieResourceTest = new DatabaseServiceResourceTest();
 | 
			
		||||
    createDatabaseService.withName("redshiftDB").withServiceType(DatabaseServiceType.Redshift);
 | 
			
		||||
    databaseService = DatabaseServiceResourceTest.createService(createDatabaseService, adminAuthHeaders());
 | 
			
		||||
    databaseService = databaseServieResourceTest.createEntity(createDatabaseService, adminAuthHeaders());
 | 
			
		||||
    REDSHIFT_REFERENCE = new DatabaseServiceEntityInterface(databaseService).getEntityReference();
 | 
			
		||||
 | 
			
		||||
    createDatabaseService.withName("bigQueryDB").withServiceType(DatabaseServiceType.BigQuery);
 | 
			
		||||
    databaseService = DatabaseServiceResourceTest.createService(createDatabaseService, adminAuthHeaders());
 | 
			
		||||
    databaseService = databaseServieResourceTest.createEntity(createDatabaseService, adminAuthHeaders());
 | 
			
		||||
    BIGQUERY_REFERENCE = new DatabaseServiceEntityInterface(databaseService).getEntityReference();
 | 
			
		||||
 | 
			
		||||
    createDatabaseService.withName("mysqlDB").withServiceType(DatabaseServiceType.MySQL);
 | 
			
		||||
    databaseService = DatabaseServiceResourceTest.createService(createDatabaseService, adminAuthHeaders());
 | 
			
		||||
    databaseService = databaseServieResourceTest.createEntity(createDatabaseService, adminAuthHeaders());
 | 
			
		||||
    MYSQL_REFERENCE = new DatabaseServiceEntityInterface(databaseService).getEntityReference();
 | 
			
		||||
 | 
			
		||||
    // Create Kafka messaging service
 | 
			
		||||
    MessagingServiceResourceTest messagingServiceResourceTest = new MessagingServiceResourceTest();
 | 
			
		||||
    CreateMessagingService createMessaging = new CreateMessagingService().withName("kafka")
 | 
			
		||||
            .withServiceType(MessagingServiceType.Kafka).withBrokers(List.of("192.168.1.1:0"));
 | 
			
		||||
    MessagingService messagingService = MessagingServiceResourceTest.createService(createMessaging, adminAuthHeaders());
 | 
			
		||||
    MessagingService messagingService = messagingServiceResourceTest.createEntity(createMessaging, adminAuthHeaders());
 | 
			
		||||
    KAFKA_REFERENCE = new MessagingServiceEntityInterface(messagingService).getEntityReference();
 | 
			
		||||
 | 
			
		||||
    // Create Pulsar messaging service
 | 
			
		||||
    createMessaging.withName("pulsar").withServiceType(MessagingServiceType.Pulsar)
 | 
			
		||||
            .withBrokers(List.of("192.168.1.1:0"));
 | 
			
		||||
    messagingService = MessagingServiceResourceTest.createService(createMessaging, adminAuthHeaders());
 | 
			
		||||
    messagingService = messagingServiceResourceTest.createEntity(createMessaging, adminAuthHeaders());
 | 
			
		||||
    PULSAR_REFERENCE = new MessagingServiceEntityInterface(messagingService).getEntityReference();
 | 
			
		||||
 | 
			
		||||
    // Create Airflow pipeline service
 | 
			
		||||
    PipelineServiceResourceTest pipelineServiceResourceTest = new PipelineServiceResourceTest();
 | 
			
		||||
    CreatePipelineService createPipeline = new CreatePipelineService().withName("airflow")
 | 
			
		||||
            .withServiceType(PipelineServiceType.Airflow).withPipelineUrl(new URI("http://localhost:0"));
 | 
			
		||||
    PipelineService pipelineService = createService(createPipeline, adminAuthHeaders());
 | 
			
		||||
    PipelineService pipelineService = pipelineServiceResourceTest.createEntity(createPipeline, adminAuthHeaders());
 | 
			
		||||
    AIRFLOW_REFERENCE = new PipelineServiceEntityInterface(pipelineService).getEntityReference();
 | 
			
		||||
 | 
			
		||||
    // Create Prefect pipeline service
 | 
			
		||||
    createPipeline.withName("prefect").withServiceType(PipelineServiceType.Prefect)
 | 
			
		||||
            .withPipelineUrl(new URI("http://localhost:0"));
 | 
			
		||||
    pipelineService = createService(createPipeline, adminAuthHeaders());
 | 
			
		||||
    pipelineService = pipelineServiceResourceTest.createEntity(createPipeline, adminAuthHeaders());
 | 
			
		||||
    PREFECT_REFERENCE = new PipelineServiceEntityInterface(pipelineService).getEntityReference();
 | 
			
		||||
 | 
			
		||||
    Tag tag = TagResourceTest.getTag("User.Address", adminAuthHeaders());
 | 
			
		||||
@ -601,7 +604,7 @@ public abstract class EntityResourceTest<T> extends CatalogApplicationTest {
 | 
			
		||||
    return TestUtils.get(target, entityClass, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected final T createEntity(Object createRequest, Map<String, String> authHeaders)
 | 
			
		||||
  public final T createEntity(Object createRequest, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    return TestUtils.post(getCollection(), createRequest, entityClass, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -75,12 +75,12 @@ public class ChartResourceTest extends EntityResourceTest<Chart> {
 | 
			
		||||
 | 
			
		||||
    CreateDashboardService createService = new CreateDashboardService().withName("superset")
 | 
			
		||||
            .withServiceType(DashboardServiceType.Superset).withDashboardUrl(new URI("http://localhost:0"));
 | 
			
		||||
    DashboardService service = DashboardServiceResourceTest.createService(createService, adminAuthHeaders());
 | 
			
		||||
    DashboardService service = new DashboardServiceResourceTest().createEntity(createService, adminAuthHeaders());
 | 
			
		||||
    SUPERSET_REFERENCE = new DashboardServiceEntityInterface(service).getEntityReference();
 | 
			
		||||
 | 
			
		||||
    createService.withName("looker").withServiceType(DashboardServiceType.Looker)
 | 
			
		||||
            .withDashboardUrl(new URI("http://localhost:0"));
 | 
			
		||||
    service = DashboardServiceResourceTest.createService(createService, adminAuthHeaders());
 | 
			
		||||
    service = new DashboardServiceResourceTest().createEntity(createService, adminAuthHeaders());
 | 
			
		||||
    LOOKER_REFERENCE = new DashboardServiceEntityInterface(service).getEntityReference();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -90,14 +90,14 @@ public class DashboardResourceTest extends EntityResourceTest<Dashboard> {
 | 
			
		||||
    CreateDashboardService createService = new CreateDashboardService().withName("superset")
 | 
			
		||||
            .withServiceType(DashboardServiceType.Superset).withDashboardUrl(TestUtils.DASHBOARD_URL);
 | 
			
		||||
 | 
			
		||||
    DashboardService service = DashboardServiceResourceTest.createService(createService, adminAuthHeaders());
 | 
			
		||||
    DashboardService service = new DashboardServiceResourceTest().createEntity(createService, adminAuthHeaders());
 | 
			
		||||
    SUPERSET_REFERENCE = new DashboardServiceEntityInterface(service).getEntityReference();
 | 
			
		||||
    SUPERSET_INVALID_SERVICE_REFERENCE = new EntityReference().withName("invalid_superset_service")
 | 
			
		||||
            .withId(SUPERSET_REFERENCE.getId())
 | 
			
		||||
            .withType("DashboardService1");
 | 
			
		||||
 | 
			
		||||
    createService.withName("looker").withServiceType(DashboardServiceType.Looker);
 | 
			
		||||
    service = DashboardServiceResourceTest.createService(createService, adminAuthHeaders());
 | 
			
		||||
    service = new DashboardServiceResourceTest().createEntity(createService, adminAuthHeaders());
 | 
			
		||||
    LOOKER_REFERENCE = new DashboardServiceEntityInterface(service).getEntityReference();
 | 
			
		||||
    CHART_REFERENCES = new ArrayList<>();
 | 
			
		||||
    for (int i=0; i < 3; i++) {
 | 
			
		||||
 | 
			
		||||
@ -95,7 +95,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
 | 
			
		||||
import static org.openmetadata.catalog.resources.databases.DatabaseResourceTest.createAndCheckDatabase;
 | 
			
		||||
import static org.openmetadata.catalog.resources.locations.LocationResourceTest.createLocation;
 | 
			
		||||
import static org.openmetadata.catalog.resources.locations.LocationResourceTest.getLocationName;
 | 
			
		||||
import static org.openmetadata.catalog.resources.services.DatabaseServiceResourceTest.createService;
 | 
			
		||||
import static org.openmetadata.catalog.type.ColumnDataType.ARRAY;
 | 
			
		||||
import static org.openmetadata.catalog.type.ColumnDataType.BIGINT;
 | 
			
		||||
import static org.openmetadata.catalog.type.ColumnDataType.BINARY;
 | 
			
		||||
@ -1052,7 +1051,7 @@ public class TableResourceTest extends EntityResourceTest<Table> {
 | 
			
		||||
    // Add location to the table
 | 
			
		||||
    CreateStorageService createService = new CreateStorageService().withName("s3")
 | 
			
		||||
            .withServiceType(StorageServiceType.S3);
 | 
			
		||||
    StorageService service = StorageServiceResourceTest.createService(createService, adminAuthHeaders());
 | 
			
		||||
    StorageService service = new StorageServiceResourceTest().createEntity(createService, adminAuthHeaders());
 | 
			
		||||
    EntityReference serviceRef =
 | 
			
		||||
            new EntityReference().withName(service.getName()).withId(service.getId()).withType(Entity.STORAGE_SERVICE);
 | 
			
		||||
    CreateLocation create = new CreateLocation().withName(getLocationName(test)).withService(serviceRef);
 | 
			
		||||
@ -1217,7 +1216,8 @@ public class TableResourceTest extends EntityResourceTest<Table> {
 | 
			
		||||
   * set up in the {@code setup()} method
 | 
			
		||||
   */
 | 
			
		||||
  public Table createEntity(TestInfo test, int index) throws IOException {
 | 
			
		||||
    DatabaseService service = createService(DatabaseServiceResourceTest.create(test), adminAuthHeaders());
 | 
			
		||||
    DatabaseService service = new DatabaseServiceResourceTest().createEntity(DatabaseServiceResourceTest.create(test),
 | 
			
		||||
            adminAuthHeaders());
 | 
			
		||||
    EntityReference serviceRef =
 | 
			
		||||
            new EntityReference().withName(service.getName()).withId(service.getId()).withType(Entity.DATABASE_SERVICE);
 | 
			
		||||
    Database database = createAndCheckDatabase(DatabaseResourceTest.create(test).withService(serviceRef),
 | 
			
		||||
 | 
			
		||||
@ -75,7 +75,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertNull;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertThrows;
 | 
			
		||||
import static org.openmetadata.catalog.resources.databases.DatabaseResourceTest.createAndCheckDatabase;
 | 
			
		||||
import static org.openmetadata.catalog.resources.services.DatabaseServiceResourceTest.createService;
 | 
			
		||||
import static org.openmetadata.catalog.type.ColumnDataType.ARRAY;
 | 
			
		||||
import static org.openmetadata.catalog.type.ColumnDataType.BIGINT;
 | 
			
		||||
import static org.openmetadata.catalog.type.ColumnDataType.BINARY;
 | 
			
		||||
@ -117,21 +116,6 @@ public class DbtModelResourceTest extends EntityResourceTest<DbtModel> {
 | 
			
		||||
    DATABASE = createAndCheckDatabase(create, adminAuthHeaders());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static DbtModel createDbtModel(TestInfo test, int i) throws IOException {
 | 
			
		||||
    return new DbtModelResourceTest().createEntity(test, i);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static DbtModel createDbtModel(CreateDbtModel createDbtModel, Map<String, String> adminAuthHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    return new DbtModelResourceTest().createEntity(createDbtModel, adminAuthHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static DbtModel createAndCheckDbtModel(CreateDbtModel createDbtModel, Map<String, String> adminAuthHeaders)
 | 
			
		||||
          throws IOException {
 | 
			
		||||
    return new DbtModelResourceTest().createAndCheckEntity(createDbtModel, adminAuthHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void post_DbtModelWithoutName_400_badRequest(TestInfo test) {
 | 
			
		||||
    // Create DbtModel with mandatory name field empty
 | 
			
		||||
@ -764,7 +748,8 @@ public class DbtModelResourceTest extends EntityResourceTest<DbtModel> {
 | 
			
		||||
   * set up in the {@code setup()} method
 | 
			
		||||
   */
 | 
			
		||||
  public DbtModel createEntity(TestInfo test, int index) throws IOException {
 | 
			
		||||
    DatabaseService service = createService(DatabaseServiceResourceTest.create(test), adminAuthHeaders());
 | 
			
		||||
    DatabaseService service = new DatabaseServiceResourceTest().createEntity(DatabaseServiceResourceTest.create(test),
 | 
			
		||||
            adminAuthHeaders());
 | 
			
		||||
    EntityReference serviceRef =
 | 
			
		||||
            new EntityReference().withName(service.getName()).withId(service.getId()).withType(Entity.DATABASE_SERVICE);
 | 
			
		||||
    Database database = createAndCheckDatabase(DatabaseResourceTest.create(test).withService(serviceRef),
 | 
			
		||||
 | 
			
		||||
@ -103,12 +103,12 @@ public class LocationResourceTest extends CatalogApplicationTest {
 | 
			
		||||
 | 
			
		||||
    CreateStorageService createService = new CreateStorageService().withName("s3")
 | 
			
		||||
            .withServiceType(StorageServiceType.S3);
 | 
			
		||||
    StorageService service = StorageServiceResourceTest.createService(createService, adminAuthHeaders());
 | 
			
		||||
    StorageService service = new StorageServiceResourceTest().createEntity(createService, adminAuthHeaders());
 | 
			
		||||
    AWS_REFERENCE = new EntityReference().withName(service.getName()).withId(service.getId())
 | 
			
		||||
            .withType(Entity.STORAGE_SERVICE);
 | 
			
		||||
 | 
			
		||||
    createService.withName("gs").withServiceType(StorageServiceType.GCS);
 | 
			
		||||
    service = StorageServiceResourceTest.createService(createService, adminAuthHeaders());
 | 
			
		||||
    service = new StorageServiceResourceTest().createEntity(createService, adminAuthHeaders());
 | 
			
		||||
    GCP_REFERENCE = new EntityReference().withName(service.getName()).withId(service.getId())
 | 
			
		||||
            .withType(Entity.STORAGE_SERVICE);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -132,7 +132,7 @@ public class MlModelResourceTest extends CatalogApplicationTest {
 | 
			
		||||
    CreateDashboardService createService = new CreateDashboardService().withName("superset")
 | 
			
		||||
            .withServiceType(DashboardServiceType.Superset).withDashboardUrl(TestUtils.DASHBOARD_URL);
 | 
			
		||||
 | 
			
		||||
    DashboardService service = DashboardServiceResourceTest.createService(createService, adminAuthHeaders());
 | 
			
		||||
    DashboardService service = new DashboardServiceResourceTest().createEntity(createService, adminAuthHeaders());
 | 
			
		||||
    SUPERSET_REFERENCE = new DashboardServiceEntityInterface(service).getEntityReference();
 | 
			
		||||
 | 
			
		||||
    DASHBOARD = DashboardResourceTest.createDashboard(
 | 
			
		||||
 | 
			
		||||
@ -25,11 +25,20 @@ 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.JsonUtils;
 | 
			
		||||
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;
 | 
			
		||||
@ -42,18 +51,24 @@ 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;
 | 
			
		||||
import static org.openmetadata.catalog.util.TestUtils.getPrincipal;
 | 
			
		||||
 | 
			
		||||
public class DashboardServiceResourceTest extends EntityResourceTest<DashboardService> {
 | 
			
		||||
  public DashboardServiceResourceTest() {
 | 
			
		||||
    super(Entity.DASHBOARD_SERVICE, DashboardService.class, DashboardServiceList.class, "services/dashboardServices",
 | 
			
		||||
            "", false, false, false);
 | 
			
		||||
    this.supportsPatch = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public class DashboardServiceResourceTest extends CatalogApplicationTest {
 | 
			
		||||
  @Test
 | 
			
		||||
  public void post_serviceWithLongName_400_badRequest(TestInfo test) throws URISyntaxException {
 | 
			
		||||
    // Create dashboard with mandatory name field empty
 | 
			
		||||
    CreateDashboardService create = create(test).withName(TestUtils.LONG_ENTITY_NAME);
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name size must be between 1 and 64]");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -61,41 +76,41 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest {
 | 
			
		||||
  public void post_withoutRequiredFields_400_badRequest(TestInfo test) {
 | 
			
		||||
    // Create dashboard with mandatory name field null
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create(test).withName(null), adminAuthHeaders()));
 | 
			
		||||
            createEntity(create(test).withName(null), adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name must not be null]");
 | 
			
		||||
 | 
			
		||||
    // Create dashboard with mandatory name field empty
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create(test).withName(""), adminAuthHeaders()));
 | 
			
		||||
            createEntity(create(test).withName(""), adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name size must be between 1 and 64]");
 | 
			
		||||
 | 
			
		||||
    // Create dashboard with mandatory serviceType field empty
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create(test).withServiceType(null), adminAuthHeaders()));
 | 
			
		||||
            createEntity(create(test).withServiceType(null), adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[serviceType must not be null]");
 | 
			
		||||
 | 
			
		||||
    // Create dashboard with mandatory brokers field empty
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create(test).withDashboardUrl(null), adminAuthHeaders()));
 | 
			
		||||
            createEntity(create(test).withDashboardUrl(null), adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[dashboardUrl must not be null]");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void post_serviceAlreadyExists_409(TestInfo test) throws HttpResponseException, URISyntaxException {
 | 
			
		||||
    CreateDashboardService create = create(test);
 | 
			
		||||
    createService(create, adminAuthHeaders());
 | 
			
		||||
    createEntity(create, adminAuthHeaders());
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, CONFLICT, CatalogExceptionMessage.ENTITY_ALREADY_EXISTS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @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<String, String> 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 +119,7 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest {
 | 
			
		||||
    Map<String, String> 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");
 | 
			
		||||
  }
 | 
			
		||||
@ -118,24 +133,24 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest {
 | 
			
		||||
    // Invalid format
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("INVALID"));
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "Invalid ingestion repeatFrequency INVALID");
 | 
			
		||||
 | 
			
		||||
    // Duration that contains years, months and seconds are not allowed
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("P1Y"));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency can only contain Days, Hours, " +
 | 
			
		||||
                    "and Minutes - example P{d}DT{h}H{m}M");
 | 
			
		||||
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("P1M"));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency can only contain Days, Hours, " +
 | 
			
		||||
                    "and Minutes - example P{d}DT{h}H{m}M");
 | 
			
		||||
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("PT1S"));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency can only contain Days, Hours, " +
 | 
			
		||||
                    "and Minutes - example P{d}DT{h}H{m}M");
 | 
			
		||||
@ -143,16 +158,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
 | 
			
		||||
@ -162,45 +177,53 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest {
 | 
			
		||||
    Schedule schedule = create.getIngestionSchedule();
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("PT1M"));  // Repeat every 0 seconds
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponseContains(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency is too short and must be more than 60 minutes");
 | 
			
		||||
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("PT59M"));  // Repeat every 50 minutes 59 seconds
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "Ingestion repeatFrequency is too short and must " +
 | 
			
		||||
            "be more than 60 minutes");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @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(schedule));
 | 
			
		||||
    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<String, String> 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");
 | 
			
		||||
  }
 | 
			
		||||
@ -208,7 +231,7 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest {
 | 
			
		||||
  @Test
 | 
			
		||||
  public void get_nonExistentService_404_notFound() {
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            getService(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
            getEntity(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND, CatalogExceptionMessage.entityNotFound(Entity.DASHBOARD_SERVICE,
 | 
			
		||||
            TestUtils.NON_EXISTENT_ENTITY));
 | 
			
		||||
  }
 | 
			
		||||
@ -221,54 +244,6 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest {
 | 
			
		||||
            "invalidName"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static DashboardService createAndCheckService(CreateDashboardService create,
 | 
			
		||||
                                                      Map<String, String> 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<String, String> 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<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    return getService(id, null, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static DashboardService getService(UUID id, String fields, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    WebTarget target = CatalogApplicationTest.getResource("services/dashboardServices/" + id);
 | 
			
		||||
    target = fields != null ? target.queryParam("fields", fields) : target;
 | 
			
		||||
    return TestUtils.get(target, DashboardService.class, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static DashboardService getServiceByName(String name, String fields, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    WebTarget target = CatalogApplicationTest.getResource("services/dashboardServices/name/" + name);
 | 
			
		||||
@ -288,14 +263,14 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest {
 | 
			
		||||
  public void delete_ExistentDashboardService_as_admin_200(TestInfo test)
 | 
			
		||||
          throws HttpResponseException, URISyntaxException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    DashboardService dashboardService = createService(create(test), authHeaders);
 | 
			
		||||
    DashboardService dashboardService = createEntity(create(test), authHeaders);
 | 
			
		||||
    deleteService(dashboardService.getId(), dashboardService.getName(), authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_as_user_401(TestInfo test) throws HttpResponseException, URISyntaxException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    DashboardService dashboardService = createService(create(test), authHeaders);
 | 
			
		||||
    DashboardService dashboardService = createEntity(create(test), authHeaders);
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            deleteService(dashboardService.getId(), dashboardService.getName(),
 | 
			
		||||
                    authHeaders("test@open-metadata.org")));
 | 
			
		||||
@ -306,7 +281,7 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest {
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_notExistentDashboardService() {
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            getService(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
            getEntity(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND,
 | 
			
		||||
            CatalogExceptionMessage.entityNotFound(Entity.DASHBOARD_SERVICE, TestUtils.NON_EXISTENT_ENTITY));
 | 
			
		||||
  }
 | 
			
		||||
@ -315,7 +290,7 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest {
 | 
			
		||||
    TestUtils.delete(CatalogApplicationTest.getResource("services/dashboardServices/" + id), authHeaders);
 | 
			
		||||
 | 
			
		||||
    // Ensure deleted service does not exist
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () -> getService(id, authHeaders));
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () -> getEntity(id, authHeaders));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND,
 | 
			
		||||
            CatalogExceptionMessage.entityNotFound(Entity.DASHBOARD_SERVICE, id));
 | 
			
		||||
 | 
			
		||||
@ -338,25 +313,52 @@ public class DashboardServiceResourceTest extends CatalogApplicationTest {
 | 
			
		||||
            .withIngestionSchedule(new Schedule().withStartDate(new Date()).withRepeatFrequency("P1D"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static void updateAndCheckService(CreateDashboardService update, Status status,
 | 
			
		||||
                                           Map<String, String> 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<String, String> authHeaders)
 | 
			
		||||
  @Override
 | 
			
		||||
  public void validateCreatedEntity(DashboardService service, Object request, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    return TestUtils.put(CatalogApplicationTest.getResource("services/dashboardServices"), updated,
 | 
			
		||||
            DashboardService.class, status, authHeaders);
 | 
			
		||||
    CreateDashboardService createRequest = (CreateDashboardService) request;
 | 
			
		||||
    validateCommonEntityFields(getEntityInterface(service), createRequest.getDescription(),
 | 
			
		||||
            getPrincipal(authHeaders), null);
 | 
			
		||||
    assertEquals(createRequest.getName(), service.getName());
 | 
			
		||||
 | 
			
		||||
    Schedule expectedIngestion = createRequest.getIngestionSchedule();
 | 
			
		||||
    if (expectedIngestion != null) {
 | 
			
		||||
      assertEquals(expectedIngestion.getStartDate(), service.getIngestionSchedule().getStartDate());
 | 
			
		||||
      assertEquals(expectedIngestion.getRepeatFrequency(), service.getIngestionSchedule().getRepeatFrequency());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void validateUpdatedEntity(DashboardService service, Object request, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    validateCreatedEntity(service, request, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void compareEntities(DashboardService expected, DashboardService updated, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    // PATCH operation is not supported by this entity
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public EntityInterface<DashboardService> getEntityInterface(DashboardService entity) {
 | 
			
		||||
    return new DashboardServiceEntityInterface(entity);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void assertFieldChange(String fieldName, Object expected, Object actual) throws IOException {
 | 
			
		||||
    if (fieldName.equals("ingestionSchedule")) {
 | 
			
		||||
      Schedule expectedSchedule = (Schedule) expected;
 | 
			
		||||
      Schedule actualSchedule = JsonUtils.readValue((String) actual, Schedule.class);
 | 
			
		||||
      assertEquals(expectedSchedule, actualSchedule);
 | 
			
		||||
    } else {
 | 
			
		||||
      super.assertCommonFieldChange(fieldName, expected, actual);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -28,14 +28,16 @@ import org.openmetadata.catalog.exception.CatalogExceptionMessage;
 | 
			
		||||
import org.openmetadata.catalog.jdbi3.DatabaseServiceRepository.DatabaseServiceEntityInterface;
 | 
			
		||||
import org.openmetadata.catalog.resources.EntityResourceTest;
 | 
			
		||||
import org.openmetadata.catalog.resources.services.database.DatabaseServiceResource.DatabaseServiceList;
 | 
			
		||||
import org.openmetadata.catalog.type.ChangeDescription;
 | 
			
		||||
import org.openmetadata.catalog.type.EntityReference;
 | 
			
		||||
import org.openmetadata.catalog.type.JdbcInfo;
 | 
			
		||||
import org.openmetadata.catalog.type.FieldChange;
 | 
			
		||||
import org.openmetadata.catalog.type.Schedule;
 | 
			
		||||
import org.openmetadata.catalog.util.EntityInterface;
 | 
			
		||||
import org.openmetadata.catalog.util.JsonUtils;
 | 
			
		||||
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.URISyntaxException;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
@ -48,10 +50,10 @@ 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;
 | 
			
		||||
import static org.openmetadata.catalog.util.TestUtils.getPrincipal;
 | 
			
		||||
 | 
			
		||||
public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseService> {
 | 
			
		||||
  public DatabaseServiceResourceTest() {
 | 
			
		||||
@ -65,7 +67,7 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
    // Create database with mandatory name field empty
 | 
			
		||||
    CreateDatabaseService create = create(test).withName(TestUtils.LONG_ENTITY_NAME);
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name size must be between 1 and 64]");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -74,16 +76,16 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
    // Create database with mandatory name field empty
 | 
			
		||||
    CreateDatabaseService create = create(test).withName("");
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name size must be between 1 and 64]");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void post_databaseServiceAlreadyExists_409(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    CreateDatabaseService create = create(test);
 | 
			
		||||
    createService(create, adminAuthHeaders());
 | 
			
		||||
    createEntity(create, adminAuthHeaders());
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, CONFLICT, CatalogExceptionMessage.ENTITY_ALREADY_EXISTS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -112,7 +114,7 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
    // No jdbc connection set
 | 
			
		||||
    CreateDatabaseService create = create(test).withJdbc(null);
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponseContains(exception, BAD_REQUEST, "jdbc must not be null");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -125,24 +127,24 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
    // Invalid format
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("INVALID"));
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "Invalid ingestion repeatFrequency INVALID");
 | 
			
		||||
 | 
			
		||||
    // Duration that contains years, months and seconds are not allowed
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("P1Y"));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency can only contain Days, Hours, " +
 | 
			
		||||
                    "and Minutes - example P{d}DT{h}H{m}M");
 | 
			
		||||
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("P1M"));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency can only contain Days, Hours, " +
 | 
			
		||||
                    "and Minutes - example P{d}DT{h}H{m}M");
 | 
			
		||||
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("PT1S"));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency can only contain Days, Hours, " +
 | 
			
		||||
                    "and Minutes - example P{d}DT{h}H{m}M");
 | 
			
		||||
@ -168,30 +170,36 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
    Schedule schedule = create.getIngestionSchedule();
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("PT1M"));  // Repeat every 0 seconds
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponseContains(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency is too short and must be more than 60 minutes");
 | 
			
		||||
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("PT59M"));  // Repeat every 50 minutes 59 seconds
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "Ingestion repeatFrequency is too short and must " +
 | 
			
		||||
            "be more than 60 minutes");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void put_updateDatabaseService_as_admin_2xx(TestInfo test) throws IOException {
 | 
			
		||||
    createAndCheckEntity(create(test).withDescription(null).withIngestionSchedule(null), adminAuthHeaders());
 | 
			
		||||
    DatabaseService service = createAndCheckEntity(create(test).withDescription(null).withIngestionSchedule(null),
 | 
			
		||||
            adminAuthHeaders());
 | 
			
		||||
 | 
			
		||||
    // Update database description and ingestion service that are null
 | 
			
		||||
    CreateDatabaseService update = create(test).withDescription("description1");
 | 
			
		||||
    updateAndCheckService(update, OK, adminAuthHeaders());
 | 
			
		||||
    // Update ingestion schedule
 | 
			
		||||
    Schedule schedule = new Schedule().withStartDate(new Date()).withRepeatFrequency("P1D");
 | 
			
		||||
    update.withIngestionSchedule(schedule);
 | 
			
		||||
    updateAndCheckService(update, OK, adminAuthHeaders());
 | 
			
		||||
    Schedule schedule = update.getIngestionSchedule();
 | 
			
		||||
    ChangeDescription change = getChangeDescription(service.getVersion());
 | 
			
		||||
    change.getFieldsAdded().add(new FieldChange().withName("description").withNewValue("description1"));
 | 
			
		||||
    change.getFieldsAdded().add(new FieldChange().withName("ingestionSchedule").withNewValue(schedule));
 | 
			
		||||
    service = updateAndCheckEntity(update, OK, adminAuthHeaders(), UpdateType.MINOR_UPDATE, change);
 | 
			
		||||
 | 
			
		||||
    // Update description and ingestion schedule again
 | 
			
		||||
    update.withDescription("description1").withIngestionSchedule(schedule.withRepeatFrequency("PT1H"));
 | 
			
		||||
    updateAndCheckService(update, OK, adminAuthHeaders());
 | 
			
		||||
    // Update ingestion schedule
 | 
			
		||||
    Schedule schedule1 = new Schedule().withStartDate(new Date()).withRepeatFrequency("PT1H");
 | 
			
		||||
    update.withIngestionSchedule(schedule1);
 | 
			
		||||
    change = getChangeDescription(service.getVersion());
 | 
			
		||||
    change.getFieldsUpdated().add(new FieldChange().withName("ingestionSchedule")
 | 
			
		||||
            .withOldValue(schedule).withNewValue(schedule1));
 | 
			
		||||
    updateAndCheckEntity(update, OK, adminAuthHeaders(), UpdateType.MINOR_UPDATE, change);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
@ -201,7 +209,8 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
 | 
			
		||||
    // Update as non admin should be forbidden
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            updateAndCheckService(create(test), OK, authHeaders("test@open-metadata.org")));
 | 
			
		||||
            updateAndCheckEntity(create(test), OK, authHeaders("test@open-metadata.org"),
 | 
			
		||||
                    UpdateType.MINOR_UPDATE, null));
 | 
			
		||||
    TestUtils.assertResponse(exception, FORBIDDEN, "Principal: CatalogPrincipal{name='test'} " +
 | 
			
		||||
            "is not admin");
 | 
			
		||||
  }
 | 
			
		||||
@ -209,7 +218,7 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
  @Test
 | 
			
		||||
  public void get_nonExistentDatabaseService_404_notFound() {
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            getService(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
            getEntity(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND, CatalogExceptionMessage.entityNotFound(Entity.DATABASE_SERVICE,
 | 
			
		||||
            TestUtils.NON_EXISTENT_ENTITY));
 | 
			
		||||
  }
 | 
			
		||||
@ -222,40 +231,6 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
            "invalidName"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static DatabaseService createService(CreateDatabaseService create,
 | 
			
		||||
                                              Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    return TestUtils.post(CatalogApplicationTest.getResource("services/databaseServices"),
 | 
			
		||||
                          create, DatabaseService.class, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void validateService(DatabaseService service, String expectedName, String expectedDescription,
 | 
			
		||||
                                      JdbcInfo expectedJdbc, Schedule expectedIngestion, String expectedUpdatedBy) {
 | 
			
		||||
    assertNotNull(service.getId());
 | 
			
		||||
    assertNotNull(service.getHref());
 | 
			
		||||
    assertEquals(expectedName, service.getName());
 | 
			
		||||
    assertEquals(expectedDescription, service.getDescription());
 | 
			
		||||
    assertEquals(expectedUpdatedBy, service.getUpdatedBy());
 | 
			
		||||
 | 
			
		||||
    // Validate jdbc
 | 
			
		||||
    assertEquals(expectedJdbc, service.getJdbc());
 | 
			
		||||
 | 
			
		||||
    if (expectedIngestion != null) {
 | 
			
		||||
      assertEquals(expectedIngestion.getStartDate(), service.getIngestionSchedule().getStartDate());
 | 
			
		||||
      assertEquals(expectedIngestion.getRepeatFrequency(), service.getIngestionSchedule().getRepeatFrequency());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static DatabaseService getService(UUID id, Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    return getService(id, null, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static DatabaseService getService(UUID id, String fields, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    WebTarget target = CatalogApplicationTest.getResource("services/databaseServices/" + id);
 | 
			
		||||
    target = fields != null ? target.queryParam("fields", fields) : target;
 | 
			
		||||
    return TestUtils.get(target, DatabaseService.class, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static DatabaseService getServiceByName(String name, String fields, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    WebTarget target = CatalogApplicationTest.getResource("services/databaseServices/name/" + name);
 | 
			
		||||
@ -274,14 +249,14 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_ExistentDatabaseService_as_admin_200(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    DatabaseService databaseService = createService(create(test), authHeaders);
 | 
			
		||||
    DatabaseService databaseService = createEntity(create(test), authHeaders);
 | 
			
		||||
    deleteService(databaseService.getId(), databaseService.getName(), authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_as_user_401(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    DatabaseService databaseService = createService(create(test), authHeaders);
 | 
			
		||||
    DatabaseService databaseService = createEntity(create(test), authHeaders);
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            deleteService(databaseService.getId(), databaseService.getName(),
 | 
			
		||||
                    authHeaders("test@open-metadata.org")));
 | 
			
		||||
@ -292,7 +267,7 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_notExistentDatabaseService() {
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            getService(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
            getEntity(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND,
 | 
			
		||||
            CatalogExceptionMessage.entityNotFound(Entity.DATABASE_SERVICE, TestUtils.NON_EXISTENT_ENTITY));
 | 
			
		||||
  }
 | 
			
		||||
@ -301,7 +276,7 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
    TestUtils.delete(CatalogApplicationTest.getResource("services/databaseServices/" + id), authHeaders);
 | 
			
		||||
 | 
			
		||||
    // Ensure deleted service does not exist
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () -> getService(id, authHeaders));
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () -> getEntity(id, authHeaders));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND, CatalogExceptionMessage.entityNotFound(Entity.DATABASE_SERVICE, id));
 | 
			
		||||
 | 
			
		||||
    // Ensure deleted service does not exist when getting by name
 | 
			
		||||
@ -321,31 +296,6 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
            .withJdbc(TestUtils.JDBC_INFO);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static void updateAndCheckService(CreateDatabaseService update, Status status,
 | 
			
		||||
                                           Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    String updatedBy = TestUtils.getPrincipal(authHeaders);
 | 
			
		||||
    DatabaseService service = updateDatabaseService(update, status, authHeaders);
 | 
			
		||||
    validateService(service, service.getName(), update.getDescription(), service.getJdbc(),
 | 
			
		||||
            update.getIngestionSchedule(), updatedBy);
 | 
			
		||||
 | 
			
		||||
    // GET the newly updated database and validate
 | 
			
		||||
    DatabaseService getService = getService(service.getId(), authHeaders);
 | 
			
		||||
    validateService(getService, service.getName(), update.getDescription(), service.getJdbc(),
 | 
			
		||||
            update.getIngestionSchedule(), updatedBy);
 | 
			
		||||
 | 
			
		||||
    // GET the newly updated database by name and validate
 | 
			
		||||
    getService = getServiceByName(service.getName(), null, authHeaders);
 | 
			
		||||
    validateService(getService, service.getName(), update.getDescription(), service.getJdbc(),
 | 
			
		||||
            update.getIngestionSchedule(), updatedBy);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static DatabaseService updateDatabaseService(CreateDatabaseService updated,
 | 
			
		||||
                                                      Status status, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    return TestUtils.put(CatalogApplicationTest.getResource("services/databaseServices"), updated,
 | 
			
		||||
            DatabaseService.class, status, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public Object createRequest(TestInfo test, int index, String description, String displayName, EntityReference owner)
 | 
			
		||||
          throws URISyntaxException {
 | 
			
		||||
@ -353,21 +303,33 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void validateCreatedEntity(DatabaseService createdEntity, Object request, Map<String, String> authHeaders)
 | 
			
		||||
  public void validateCreatedEntity(DatabaseService service, Object request, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    CreateDatabaseService createRequest = (CreateDatabaseService) request;
 | 
			
		||||
    validateCommonEntityFields(getEntityInterface(service), createRequest.getDescription(), getPrincipal(authHeaders),
 | 
			
		||||
            null);
 | 
			
		||||
    assertEquals(createRequest.getName(), service.getName());
 | 
			
		||||
 | 
			
		||||
    // Validate jdbc
 | 
			
		||||
    assertEquals(createRequest.getJdbc(), service.getJdbc());
 | 
			
		||||
 | 
			
		||||
    Schedule expectedIngestion = createRequest.getIngestionSchedule();
 | 
			
		||||
    if (expectedIngestion != null) {
 | 
			
		||||
      assertEquals(expectedIngestion.getStartDate(), service.getIngestionSchedule().getStartDate());
 | 
			
		||||
      assertEquals(expectedIngestion.getRepeatFrequency(), service.getIngestionSchedule().getRepeatFrequency());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void validateUpdatedEntity(DatabaseService updatedEntity, Object request, Map<String, String> authHeaders)
 | 
			
		||||
  public void validateUpdatedEntity(DatabaseService service, Object request, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
 | 
			
		||||
    validateCreatedEntity(service, request, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void compareEntities(DatabaseService expected, DatabaseService updated, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
 | 
			
		||||
    // PATCH operation is not supported by this entity
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
@ -377,6 +339,12 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void assertFieldChange(String fieldName, Object expected, Object actual) throws IOException {
 | 
			
		||||
 | 
			
		||||
    if (fieldName.equals("ingestionSchedule")) {
 | 
			
		||||
      Schedule expectedSchedule = (Schedule) expected;
 | 
			
		||||
      Schedule actualSchedule = JsonUtils.readValue((String) actual, Schedule.class);
 | 
			
		||||
      assertEquals(expectedSchedule, actualSchedule);
 | 
			
		||||
    } else {
 | 
			
		||||
      super.assertCommonFieldChange(fieldName, expected, actual);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -29,13 +29,16 @@ import org.openmetadata.catalog.exception.CatalogExceptionMessage;
 | 
			
		||||
import org.openmetadata.catalog.jdbi3.MessagingServiceRepository.MessagingServiceEntityInterface;
 | 
			
		||||
import org.openmetadata.catalog.resources.EntityResourceTest;
 | 
			
		||||
import org.openmetadata.catalog.resources.services.messaging.MessagingServiceResource.MessagingServiceList;
 | 
			
		||||
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.JsonUtils;
 | 
			
		||||
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;
 | 
			
		||||
@ -50,7 +53,6 @@ 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.junit.jupiter.api.Assertions.assertTrue;
 | 
			
		||||
import static org.openmetadata.catalog.util.TestUtils.adminAuthHeaders;
 | 
			
		||||
@ -78,7 +80,7 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
    // Create messaging with mandatory name field empty
 | 
			
		||||
    CreateMessagingService create = create(test).withName(TestUtils.LONG_ENTITY_NAME);
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name size must be between 1 and 64]");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -86,31 +88,31 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
  public void post_withoutRequiredFields_400_badRequest(TestInfo test) {
 | 
			
		||||
    // Create messaging with mandatory name field null
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create(test).withName(null), adminAuthHeaders()));
 | 
			
		||||
            createEntity(create(test).withName(null), adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name must not be null]");
 | 
			
		||||
 | 
			
		||||
    // Create messaging with mandatory name field empty
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create(test).withName(""), adminAuthHeaders()));
 | 
			
		||||
            createEntity(create(test).withName(""), adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name size must be between 1 and 64]");
 | 
			
		||||
 | 
			
		||||
    // Create messaging with mandatory serviceType field empty
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create(test).withServiceType(null), adminAuthHeaders()));
 | 
			
		||||
            createEntity(create(test).withServiceType(null), adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[serviceType must not be null]");
 | 
			
		||||
 | 
			
		||||
    // Create messaging with mandatory brokers field empty
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create(test).withBrokers(null), adminAuthHeaders()));
 | 
			
		||||
            createEntity(create(test).withBrokers(null), adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[brokers must not be null]");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void post_serviceAlreadyExists_409(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    CreateMessagingService create = create(test);
 | 
			
		||||
    createService(create, adminAuthHeaders());
 | 
			
		||||
    createEntity(create, adminAuthHeaders());
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, CONFLICT, CatalogExceptionMessage.ENTITY_ALREADY_EXISTS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -143,24 +145,24 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
    // Invalid format
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("INVALID"));
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "Invalid ingestion repeatFrequency INVALID");
 | 
			
		||||
 | 
			
		||||
    // Duration that contains years, months and seconds are not allowed
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("P1Y"));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency can only contain Days, Hours, " +
 | 
			
		||||
                    "and Minutes - example P{d}DT{h}H{m}M");
 | 
			
		||||
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("P1M"));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency can only contain Days, Hours, " +
 | 
			
		||||
                    "and Minutes - example P{d}DT{h}H{m}M");
 | 
			
		||||
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("PT1S"));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency can only contain Days, Hours, " +
 | 
			
		||||
                    "and Minutes - example P{d}DT{h}H{m}M");
 | 
			
		||||
@ -186,50 +188,65 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
    Schedule schedule = create.getIngestionSchedule();
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("PT1M"));  // Repeat every 0 seconds
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponseContains(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency is too short and must be more than 60 minutes");
 | 
			
		||||
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("PT59M"));  // Repeat every 50 minutes 59 seconds
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "Ingestion repeatFrequency is too short and must " +
 | 
			
		||||
            "be more than 60 minutes");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void put_updateService_as_admin_2xx(TestInfo test) throws IOException, URISyntaxException {
 | 
			
		||||
    MessagingService dbService = createAndCheckEntity(create(test).withDescription(null).withIngestionSchedule(null)
 | 
			
		||||
    MessagingService service = createAndCheckEntity(create(test).withDescription(null).withIngestionSchedule(null)
 | 
			
		||||
            .withBrokers(KAFKA_BROKERS).withSchemaRegistry(SCHEMA_REGISTRY_URL), adminAuthHeaders());
 | 
			
		||||
 | 
			
		||||
    // Update messaging description and ingestion service that are null
 | 
			
		||||
    CreateMessagingService update = create(test).withDescription("description1").withIngestionSchedule(null);
 | 
			
		||||
    updateAndCheckService(update, OK, adminAuthHeaders());
 | 
			
		||||
    ChangeDescription change = getChangeDescription(service.getVersion());
 | 
			
		||||
    change.getFieldsAdded().add(new FieldChange().withName("description").withNewValue("description1"));
 | 
			
		||||
    service = updateAndCheckEntity(update, OK, adminAuthHeaders(), UpdateType.MINOR_UPDATE, change);
 | 
			
		||||
 | 
			
		||||
    // Update ingestion schedule
 | 
			
		||||
    Schedule schedule = new Schedule().withStartDate(new Date()).withRepeatFrequency("P1D");
 | 
			
		||||
    change = getChangeDescription(service.getVersion());
 | 
			
		||||
    change.getFieldsAdded().add(new FieldChange().withName("ingestionSchedule").withNewValue(schedule));
 | 
			
		||||
    update.withIngestionSchedule(schedule);
 | 
			
		||||
    updateAndCheckService(update, OK, adminAuthHeaders());
 | 
			
		||||
    service = updateAndCheckEntity(update, OK, adminAuthHeaders(), UpdateType.MINOR_UPDATE, change);
 | 
			
		||||
 | 
			
		||||
    // 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");
 | 
			
		||||
    update.withIngestionSchedule(schedule1);
 | 
			
		||||
    change = getChangeDescription(service.getVersion());
 | 
			
		||||
    change.getFieldsUpdated().add(new FieldChange().withName("ingestionSchedule")
 | 
			
		||||
            .withOldValue(schedule).withNewValue(schedule1));
 | 
			
		||||
    service = updateAndCheckEntity(update, OK, adminAuthHeaders(), UpdateType.MINOR_UPDATE, change);
 | 
			
		||||
 | 
			
		||||
    // update broker list and schema registry
 | 
			
		||||
    update.withBrokers(List.of("localhost:0")).withSchemaRegistry(new URI("http://localhost:9000"));
 | 
			
		||||
    updateAndCheckService(update, OK, adminAuthHeaders());
 | 
			
		||||
    MessagingService updatedService = getService(dbService.getId(), adminAuthHeaders());
 | 
			
		||||
    validateMessagingServiceConfig(updatedService, List.of("localhost:0"), new URI("http://localhost:9000"));
 | 
			
		||||
    List<String> updatedBrokers = List.of("localhost:0");
 | 
			
		||||
    URI updatedSchemaRegistry = new URI("http://localhost:9000");
 | 
			
		||||
    update.withBrokers(updatedBrokers).withSchemaRegistry(updatedSchemaRegistry);
 | 
			
		||||
 | 
			
		||||
    change = getChangeDescription(service.getVersion());
 | 
			
		||||
    change.getFieldsDeleted().add(new FieldChange().withName("brokers").withOldValue(KAFKA_BROKERS));
 | 
			
		||||
    change.getFieldsAdded().add(new FieldChange().withName("brokers").withNewValue(updatedBrokers));
 | 
			
		||||
    change.getFieldsUpdated().add(new FieldChange().withName("schemaRegistry")
 | 
			
		||||
            .withOldValue(SCHEMA_REGISTRY_URL).withNewValue(updatedSchemaRegistry));
 | 
			
		||||
 | 
			
		||||
    updateAndCheckEntity(update, OK, adminAuthHeaders(), UpdateType.MINOR_UPDATE, change);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void put_update_as_non_admin_401(TestInfo test) throws IOException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    MessagingService dbService = createAndCheckEntity(create(test).withDescription(null).withIngestionSchedule(null),
 | 
			
		||||
            authHeaders);
 | 
			
		||||
    createAndCheckEntity(create(test).withDescription(null).withIngestionSchedule(null), authHeaders);
 | 
			
		||||
 | 
			
		||||
    // Update messaging description as non admin and expect exception
 | 
			
		||||
    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");
 | 
			
		||||
  }
 | 
			
		||||
@ -237,7 +254,7 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
  @Test
 | 
			
		||||
  public void get_nonExistentService_404_notFound() {
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            getService(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
            getEntity(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND, CatalogExceptionMessage.entityNotFound(Entity.MESSAGING_SERVICE,
 | 
			
		||||
            TestUtils.NON_EXISTENT_ENTITY));
 | 
			
		||||
  }
 | 
			
		||||
@ -250,37 +267,6 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
            "invalidName"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static MessagingService createService(CreateMessagingService create,
 | 
			
		||||
                                              Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    return TestUtils.post(CatalogApplicationTest.getResource("services/messagingServices"),
 | 
			
		||||
                          create, MessagingService.class, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void validateService(MessagingService 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 MessagingService getService(UUID id, Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    return getService(id, null, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static MessagingService getService(UUID id, String fields, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    WebTarget target = CatalogApplicationTest.getResource("services/messagingServices/" + id);
 | 
			
		||||
    target = fields != null ? target.queryParam("fields", fields) : target;
 | 
			
		||||
    return TestUtils.get(target, MessagingService.class, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static MessagingService getServiceByName(String name, String fields, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    WebTarget target = CatalogApplicationTest.getResource("services/messagingServices/name/" + name);
 | 
			
		||||
@ -299,14 +285,14 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_ExistentMessagingService_as_admin_200(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    MessagingService messagingService = createService(create(test), authHeaders);
 | 
			
		||||
    MessagingService messagingService = createEntity(create(test), authHeaders);
 | 
			
		||||
    deleteService(messagingService.getId(), messagingService.getName(), authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_as_user_401(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    MessagingService messagingService = createService(create(test), authHeaders);
 | 
			
		||||
    MessagingService messagingService = createEntity(create(test), authHeaders);
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            deleteService(messagingService.getId(), messagingService.getName(),
 | 
			
		||||
                    authHeaders("test@open-metadata.org")));
 | 
			
		||||
@ -317,7 +303,7 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_notExistentMessagingService() {
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            getService(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
            getEntity(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND,
 | 
			
		||||
            CatalogExceptionMessage.entityNotFound(Entity.MESSAGING_SERVICE, TestUtils.NON_EXISTENT_ENTITY));
 | 
			
		||||
  }
 | 
			
		||||
@ -326,7 +312,7 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
    TestUtils.delete(CatalogApplicationTest.getResource("services/messagingServices/" + id), authHeaders);
 | 
			
		||||
 | 
			
		||||
    // Ensure deleted service does not exist
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () -> getService(id, authHeaders));
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () -> getEntity(id, authHeaders));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND,
 | 
			
		||||
            CatalogExceptionMessage.entityNotFound(Entity.MESSAGING_SERVICE, id));
 | 
			
		||||
 | 
			
		||||
@ -349,34 +335,6 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
            .withIngestionSchedule(new Schedule().withStartDate(new Date()).withRepeatFrequency("P1D"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static void updateAndCheckService(CreateMessagingService update, Status status,
 | 
			
		||||
                                           Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    String updatedBy = TestUtils.getPrincipal(authHeaders);
 | 
			
		||||
    MessagingService service = updateMessagingService(update, status, authHeaders);
 | 
			
		||||
    validateService(service, update.getName(), update.getDescription(), update.getIngestionSchedule(), updatedBy);
 | 
			
		||||
 | 
			
		||||
    // GET the newly updated messaging and validate
 | 
			
		||||
    MessagingService getService = getService(service.getId(), authHeaders);
 | 
			
		||||
    validateService(getService, update.getName(), update.getDescription(), update.getIngestionSchedule(), updatedBy);
 | 
			
		||||
 | 
			
		||||
    // GET the newly updated messaging by name and validate
 | 
			
		||||
    getService = getServiceByName(service.getName(), null, authHeaders);
 | 
			
		||||
    validateService(getService, update.getName(), update.getDescription(), update.getIngestionSchedule(), updatedBy);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static MessagingService updateMessagingService(CreateMessagingService updated,
 | 
			
		||||
                                                      Status status, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    return TestUtils.put(CatalogApplicationTest.getResource("services/messagingServices"), updated,
 | 
			
		||||
            MessagingService.class, status, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void validateMessagingServiceConfig(MessagingService actualService, List<String> expectedBrokers,
 | 
			
		||||
                                                     URI expectedSchemaRegistry) {
 | 
			
		||||
    assertTrue(actualService.getBrokers().containsAll(expectedBrokers));
 | 
			
		||||
    assertEquals(actualService.getSchemaRegistry(), expectedSchemaRegistry);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public Object createRequest(TestInfo test, int index, String description, String displayName, EntityReference owner)
 | 
			
		||||
          throws URISyntaxException {
 | 
			
		||||
@ -394,6 +352,8 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
      assertEquals(expectedIngestion.getStartDate(), service.getIngestionSchedule().getStartDate());
 | 
			
		||||
      assertEquals(expectedIngestion.getRepeatFrequency(), service.getIngestionSchedule().getRepeatFrequency());
 | 
			
		||||
    }
 | 
			
		||||
    assertTrue(createRequest.getBrokers().containsAll(service.getBrokers()));
 | 
			
		||||
    assertEquals(createRequest.getSchemaRegistry(), service.getSchemaRegistry());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
@ -405,6 +365,7 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
  @Override
 | 
			
		||||
  public void compareEntities(MessagingService expected, MessagingService updated, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    // PATCH operation is not supported by this entity
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
@ -414,6 +375,20 @@ public class MessagingServiceResourceTest extends EntityResourceTest<MessagingSe
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void assertFieldChange(String fieldName, Object expected, Object actual) throws IOException {
 | 
			
		||||
    return; // TODO
 | 
			
		||||
    if (fieldName.equals("ingestionSchedule")) {
 | 
			
		||||
      Schedule expectedSchedule = (Schedule) expected;
 | 
			
		||||
      Schedule actualSchedule = JsonUtils.readValue((String) actual, Schedule.class);
 | 
			
		||||
      assertEquals(expectedSchedule, actualSchedule);
 | 
			
		||||
    } else if (fieldName.equals("brokers")) {
 | 
			
		||||
      List<String> expectedBrokers = (List<String>) expected;
 | 
			
		||||
      List<String> actualBrokers = JsonUtils.readObjects((String) actual, String.class);
 | 
			
		||||
      assertEquals(expectedBrokers, actualBrokers);
 | 
			
		||||
    } else if (fieldName.equals("schemaRegistry")) {
 | 
			
		||||
      URI expectedUri = (URI) expected;
 | 
			
		||||
      URI actualUri = URI.create((String) actual);
 | 
			
		||||
      assertEquals(expectedUri, actualUri);
 | 
			
		||||
    } else {
 | 
			
		||||
      super.assertCommonFieldChange(fieldName, expected, actual);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -28,18 +28,20 @@ import org.openmetadata.catalog.exception.CatalogExceptionMessage;
 | 
			
		||||
import org.openmetadata.catalog.jdbi3.PipelineServiceRepository.PipelineServiceEntityInterface;
 | 
			
		||||
import org.openmetadata.catalog.resources.EntityResourceTest;
 | 
			
		||||
import org.openmetadata.catalog.resources.services.pipeline.PipelineServiceResource.PipelineServiceList;
 | 
			
		||||
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.JsonUtils;
 | 
			
		||||
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;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
@ -49,10 +51,10 @@ 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;
 | 
			
		||||
import static org.openmetadata.catalog.util.TestUtils.getPrincipal;
 | 
			
		||||
 | 
			
		||||
public class PipelineServiceResourceTest extends EntityResourceTest<PipelineService> {
 | 
			
		||||
 | 
			
		||||
@ -65,50 +67,17 @@ public class PipelineServiceResourceTest extends EntityResourceTest<PipelineServ
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @BeforeAll
 | 
			
		||||
  public static void setup() throws URISyntaxException {
 | 
			
		||||
  public static void setup(TestInfo test) throws URISyntaxException, IOException {
 | 
			
		||||
    EntityResourceTest.setup(test);
 | 
			
		||||
    PIPELINE_SERVICE_URL = new URI("http://localhost:8080");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public Object createRequest(TestInfo test, int index, String description, String displayName, EntityReference owner)
 | 
			
		||||
          throws URISyntaxException {
 | 
			
		||||
    return create(test, index).withDescription(description).withIngestionSchedule(null);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void validateCreatedEntity(PipelineService createdEntity, Object request, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void validateUpdatedEntity(PipelineService updatedEntity, Object request, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void compareEntities(PipelineService expected, PipelineService updated, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public EntityInterface<PipelineService> getEntityInterface(PipelineService entity) {
 | 
			
		||||
    return new PipelineServiceEntityInterface(entity);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void assertFieldChange(String fieldName, Object expected, Object actual) throws IOException {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void post_serviceWithLongName_400_badRequest(TestInfo test) {
 | 
			
		||||
    // Create pipeline with mandatory name field empty
 | 
			
		||||
    CreatePipelineService create = create(test).withName(TestUtils.LONG_ENTITY_NAME);
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name size must be between 1 and 64]");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -116,41 +85,41 @@ public class PipelineServiceResourceTest extends EntityResourceTest<PipelineServ
 | 
			
		||||
  public void post_withoutRequiredFields_400_badRequest(TestInfo test) {
 | 
			
		||||
    // Create pipeline with mandatory name field null
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create(test).withName(null), adminAuthHeaders()));
 | 
			
		||||
            createEntity(create(test).withName(null), adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name must not be null]");
 | 
			
		||||
 | 
			
		||||
    // Create pipeline with mandatory name field empty
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create(test).withName(""), adminAuthHeaders()));
 | 
			
		||||
            createEntity(create(test).withName(""), adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name size must be between 1 and 64]");
 | 
			
		||||
 | 
			
		||||
    // Create pipeline with mandatory serviceType field empty
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create(test).withServiceType(null), adminAuthHeaders()));
 | 
			
		||||
            createEntity(create(test).withServiceType(null), adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[serviceType must not be null]");
 | 
			
		||||
 | 
			
		||||
    // Create pipeline with mandatory brokers field empty
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create(test).withPipelineUrl(null), adminAuthHeaders()));
 | 
			
		||||
            createEntity(create(test).withPipelineUrl(null), adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[pipelineUrl must not be null]");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void post_serviceAlreadyExists_409(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    CreatePipelineService create = create(test);
 | 
			
		||||
    createService(create, adminAuthHeaders());
 | 
			
		||||
    createEntity(create, adminAuthHeaders());
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, CONFLICT, CatalogExceptionMessage.ENTITY_ALREADY_EXISTS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void post_validService_as_admin_200_ok(TestInfo test) throws HttpResponseException {
 | 
			
		||||
  public void post_validService_as_admin_200_ok(TestInfo test) throws IOException {
 | 
			
		||||
    // Create pipeline service with different optional fields
 | 
			
		||||
    Map<String, String> 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
 | 
			
		||||
@ -159,7 +128,7 @@ public class PipelineServiceResourceTest extends EntityResourceTest<PipelineServ
 | 
			
		||||
    Map<String, String> 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");
 | 
			
		||||
  }
 | 
			
		||||
@ -173,40 +142,40 @@ public class PipelineServiceResourceTest extends EntityResourceTest<PipelineServ
 | 
			
		||||
    // Invalid format
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("INVALID"));
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "Invalid ingestion repeatFrequency INVALID");
 | 
			
		||||
 | 
			
		||||
    // Duration that contains years, months and seconds are not allowed
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("P1Y"));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency can only contain Days, Hours, " +
 | 
			
		||||
                    "and Minutes - example P{d}DT{h}H{m}M");
 | 
			
		||||
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("P1M"));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency can only contain Days, Hours, " +
 | 
			
		||||
                    "and Minutes - example P{d}DT{h}H{m}M");
 | 
			
		||||
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("PT1S"));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency can only contain Days, Hours, " +
 | 
			
		||||
                    "and Minutes - example P{d}DT{h}H{m}M");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void post_validIngestionSchedules_as_admin_200(TestInfo test) throws HttpResponseException {
 | 
			
		||||
  public void post_validIngestionSchedules_as_admin_200(TestInfo test) throws IOException {
 | 
			
		||||
    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
 | 
			
		||||
@ -216,51 +185,55 @@ public class PipelineServiceResourceTest extends EntityResourceTest<PipelineServ
 | 
			
		||||
    Schedule schedule = create.getIngestionSchedule();
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("PT1M"));  // Repeat every 0 seconds
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponseContains(exception, BAD_REQUEST,
 | 
			
		||||
            "Ingestion repeatFrequency is too short and must be more than 60 minutes");
 | 
			
		||||
 | 
			
		||||
    create.withIngestionSchedule(schedule.withRepeatFrequency("PT59M"));  // Repeat every 50 minutes 59 seconds
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createService(create, adminAuthHeaders()));
 | 
			
		||||
    exception = assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "Ingestion repeatFrequency is too short and must " +
 | 
			
		||||
            "be more than 60 minutes");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void put_updateService_as_admin_2xx(TestInfo test) throws HttpResponseException, URISyntaxException {
 | 
			
		||||
    PipelineService dbService = createAndCheckService(create(test).withDescription(null).withIngestionSchedule(null)
 | 
			
		||||
  public void put_updateService_as_admin_2xx(TestInfo test) throws IOException, URISyntaxException {
 | 
			
		||||
    PipelineService service = createAndCheckEntity(create(test).withDescription(null).withIngestionSchedule(null)
 | 
			
		||||
            .withPipelineUrl(PIPELINE_SERVICE_URL), adminAuthHeaders());
 | 
			
		||||
 | 
			
		||||
    // Update pipeline description and ingestion service that are null
 | 
			
		||||
    CreatePipelineService update = create(test).withDescription("description1");
 | 
			
		||||
    updateAndCheckService(update, OK, adminAuthHeaders());
 | 
			
		||||
    Schedule schedule = update.getIngestionSchedule();
 | 
			
		||||
    ChangeDescription change = getChangeDescription(service.getVersion());
 | 
			
		||||
    change.getFieldsAdded().add(new FieldChange().withName("description").withNewValue("description1"));
 | 
			
		||||
    change.getFieldsAdded().add(new FieldChange().withName("ingestionSchedule").withNewValue(schedule));
 | 
			
		||||
    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 ingestion schedule again
 | 
			
		||||
    Schedule schedule1 = new Schedule().withStartDate(new Date()).withRepeatFrequency("PT1H");
 | 
			
		||||
    update.withIngestionSchedule(schedule1);
 | 
			
		||||
    change = getChangeDescription(service.getVersion());
 | 
			
		||||
    change.getFieldsUpdated().add(new FieldChange().withName("ingestionSchedule").withOldValue(schedule)
 | 
			
		||||
            .withNewValue(schedule1));
 | 
			
		||||
    service = updateAndCheckEntity(update, OK, adminAuthHeaders(), UpdateType.MINOR_UPDATE, change);
 | 
			
		||||
 | 
			
		||||
    // Update  ingestion schedule again
 | 
			
		||||
    update.withIngestionSchedule(schedule.withRepeatFrequency("PT1H"));
 | 
			
		||||
    updateAndCheckService(update, OK, adminAuthHeaders());
 | 
			
		||||
 | 
			
		||||
    // update broker list and schema registry
 | 
			
		||||
    update.withPipelineUrl(new URI("http://localhost:9000"));
 | 
			
		||||
    updateAndCheckService(update, OK, adminAuthHeaders());
 | 
			
		||||
    PipelineService updatedService = getService(dbService.getId(), adminAuthHeaders());
 | 
			
		||||
    validatePipelineServiceConfig(updatedService, List.of("localhost:0"), new URI("http://localhost:9000"));
 | 
			
		||||
    // update pipeline Url
 | 
			
		||||
    URI pipelineUrl = new URI("http://localhost:9000");
 | 
			
		||||
    update.withPipelineUrl(pipelineUrl);
 | 
			
		||||
    change = getChangeDescription(service.getVersion());
 | 
			
		||||
    change.getFieldsUpdated().add(new FieldChange().withName("pipelineUrl")
 | 
			
		||||
            .withOldValue(PIPELINE_SERVICE_URL).withNewValue(pipelineUrl));
 | 
			
		||||
    updateAndCheckEntity(update, OK, adminAuthHeaders(), UpdateType.MINOR_UPDATE, change);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void put_update_as_non_admin_401(TestInfo test) throws HttpResponseException {
 | 
			
		||||
  public void put_update_as_non_admin_401(TestInfo test) throws IOException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    PipelineService pipelineService = createAndCheckService(create(test).withDescription(null)
 | 
			
		||||
                    .withIngestionSchedule(null),
 | 
			
		||||
            authHeaders);
 | 
			
		||||
    createAndCheckEntity(create(test).withDescription(null) .withIngestionSchedule(null), authHeaders);
 | 
			
		||||
 | 
			
		||||
    // Update pipeline 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");
 | 
			
		||||
  }
 | 
			
		||||
@ -268,7 +241,7 @@ public class PipelineServiceResourceTest extends EntityResourceTest<PipelineServ
 | 
			
		||||
  @Test
 | 
			
		||||
  public void get_nonExistentService_404_notFound() {
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            getService(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
            getEntity(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND, CatalogExceptionMessage.entityNotFound(Entity.PIPELINE_SERVICE,
 | 
			
		||||
            TestUtils.NON_EXISTENT_ENTITY));
 | 
			
		||||
  }
 | 
			
		||||
@ -281,54 +254,6 @@ public class PipelineServiceResourceTest extends EntityResourceTest<PipelineServ
 | 
			
		||||
            "invalidName"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static PipelineService createAndCheckService(CreatePipelineService create,
 | 
			
		||||
                                                      Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    String updatedBy = TestUtils.getPrincipal(authHeaders);
 | 
			
		||||
    PipelineService service = createService(create, authHeaders);
 | 
			
		||||
    assertEquals(0.1, service.getVersion());
 | 
			
		||||
    validateService(service, create.getName(), create.getDescription(), create.getIngestionSchedule(), updatedBy);
 | 
			
		||||
 | 
			
		||||
    // GET the newly created service and validate
 | 
			
		||||
    PipelineService 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 PipelineService createService(CreatePipelineService create,
 | 
			
		||||
                                              Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    return TestUtils.post(CatalogApplicationTest.getResource("services/pipelineServices"),
 | 
			
		||||
                          create, PipelineService.class, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void validateService(PipelineService 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 PipelineService getService(UUID id, Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    return getService(id, null, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static PipelineService getService(UUID id, String fields, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    WebTarget target = CatalogApplicationTest.getResource("services/pipelineServices/" + id);
 | 
			
		||||
    target = fields != null ? target.queryParam("fields", fields) : target;
 | 
			
		||||
    return TestUtils.get(target, PipelineService.class, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static PipelineService getServiceByName(String name, String fields, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    WebTarget target = CatalogApplicationTest.getResource("services/pipelineServices/name/" + name);
 | 
			
		||||
@ -347,14 +272,14 @@ public class PipelineServiceResourceTest extends EntityResourceTest<PipelineServ
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_ExistentPipelineService_as_admin_200(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    PipelineService pipelineService = createService(create(test), authHeaders);
 | 
			
		||||
    PipelineService pipelineService = createEntity(create(test), authHeaders);
 | 
			
		||||
    deleteService(pipelineService.getId(), pipelineService.getName(), authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_as_user_401(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    PipelineService pipelineService = createService(create(test), authHeaders);
 | 
			
		||||
    PipelineService pipelineService = createEntity(create(test), authHeaders);
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            deleteService(pipelineService.getId(), pipelineService.getName(),
 | 
			
		||||
                    authHeaders("test@open-metadata.org")));
 | 
			
		||||
@ -365,7 +290,7 @@ public class PipelineServiceResourceTest extends EntityResourceTest<PipelineServ
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_notExistentPipelineService() {
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            getService(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
            getEntity(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND,
 | 
			
		||||
            CatalogExceptionMessage.entityNotFound(Entity.PIPELINE_SERVICE, TestUtils.NON_EXISTENT_ENTITY));
 | 
			
		||||
  }
 | 
			
		||||
@ -374,7 +299,7 @@ public class PipelineServiceResourceTest extends EntityResourceTest<PipelineServ
 | 
			
		||||
    TestUtils.delete(CatalogApplicationTest.getResource("services/pipelineServices/" + id), authHeaders);
 | 
			
		||||
 | 
			
		||||
    // Ensure deleted service does not exist
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () -> getService(id, authHeaders));
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () -> getEntity(id, authHeaders));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND,
 | 
			
		||||
            CatalogExceptionMessage.entityNotFound(Entity.PIPELINE_SERVICE, id));
 | 
			
		||||
 | 
			
		||||
@ -398,30 +323,57 @@ public class PipelineServiceResourceTest extends EntityResourceTest<PipelineServ
 | 
			
		||||
            .withIngestionSchedule(new Schedule().withStartDate(new Date()).withRepeatFrequency("P1D"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static void updateAndCheckService(CreatePipelineService update, Status status,
 | 
			
		||||
                                           Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    String updatedBy = TestUtils.getPrincipal(authHeaders);
 | 
			
		||||
    PipelineService service = updatePipelineService(update, status, authHeaders);
 | 
			
		||||
    validateService(service, service.getName(), update.getDescription(), update.getIngestionSchedule(), updatedBy);
 | 
			
		||||
 | 
			
		||||
    // GET the newly updated pipeline and validate
 | 
			
		||||
    PipelineService getService = getService(service.getId(), authHeaders);
 | 
			
		||||
    validateService(getService, service.getName(), update.getDescription(), update.getIngestionSchedule(), updatedBy);
 | 
			
		||||
 | 
			
		||||
    // GET the newly updated pipeline 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 PipelineService updatePipelineService(CreatePipelineService updated,
 | 
			
		||||
                                                      Status status, Map<String, String> authHeaders)
 | 
			
		||||
  @Override
 | 
			
		||||
  public void validateCreatedEntity(PipelineService service, Object request, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    return TestUtils.put(CatalogApplicationTest.getResource("services/pipelineServices"), updated,
 | 
			
		||||
            PipelineService.class, status, authHeaders);
 | 
			
		||||
    CreatePipelineService createRequest = (CreatePipelineService) request;
 | 
			
		||||
    validateCommonEntityFields(getEntityInterface(service), createRequest.getDescription(), getPrincipal(authHeaders),
 | 
			
		||||
            null);
 | 
			
		||||
    assertEquals(createRequest.getName(), service.getName());
 | 
			
		||||
 | 
			
		||||
    Schedule expectedIngestion = createRequest.getIngestionSchedule();
 | 
			
		||||
    if (expectedIngestion != null) {
 | 
			
		||||
      assertEquals(expectedIngestion.getStartDate(), service.getIngestionSchedule().getStartDate());
 | 
			
		||||
      assertEquals(expectedIngestion.getRepeatFrequency(), service.getIngestionSchedule().getRepeatFrequency());
 | 
			
		||||
    }
 | 
			
		||||
    assertEquals(createRequest.getPipelineUrl(), service.getPipelineUrl());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void validatePipelineServiceConfig(PipelineService actualService, List<String> expectedBrokers,
 | 
			
		||||
                                                     URI expectedUrl) {
 | 
			
		||||
    assertEquals(actualService.getPipelineUrl(), expectedUrl);
 | 
			
		||||
  @Override
 | 
			
		||||
  public void validateUpdatedEntity(PipelineService updatedEntity, Object request, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    validateCreatedEntity(updatedEntity, request, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void compareEntities(PipelineService expected, PipelineService updated, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    // PATCH operation is not supported by this entity
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public EntityInterface<PipelineService> getEntityInterface(PipelineService entity) {
 | 
			
		||||
    return new PipelineServiceEntityInterface(entity);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void assertFieldChange(String fieldName, Object expected, Object actual) throws IOException {
 | 
			
		||||
    if (fieldName.equals("ingestionSchedule")) {
 | 
			
		||||
      Schedule expectedSchedule = (Schedule) expected;
 | 
			
		||||
      Schedule actualSchedule = JsonUtils.readValue((String) actual, Schedule.class);
 | 
			
		||||
      assertEquals(expectedSchedule, actualSchedule);
 | 
			
		||||
    } else if (fieldName.equals("pipelineUrl")) {
 | 
			
		||||
      URI expectedUri = (URI) expected;
 | 
			
		||||
      URI actualUri = URI.create((String) actual);
 | 
			
		||||
      assertEquals(expectedUri, actualUri);
 | 
			
		||||
    } else {
 | 
			
		||||
      super.assertCommonFieldChange(fieldName, expected, actual);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -15,9 +15,9 @@ import org.openmetadata.catalog.type.EntityReference;
 | 
			
		||||
import org.openmetadata.catalog.type.StorageServiceType;
 | 
			
		||||
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;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.URISyntaxException;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
@ -29,10 +29,10 @@ 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;
 | 
			
		||||
import static org.openmetadata.catalog.util.TestUtils.getPrincipal;
 | 
			
		||||
 | 
			
		||||
public class StorageServiceResourceTest extends EntityResourceTest<StorageService> {
 | 
			
		||||
  public StorageServiceResourceTest() {
 | 
			
		||||
@ -46,7 +46,7 @@ public class StorageServiceResourceTest extends EntityResourceTest<StorageServic
 | 
			
		||||
    // Create storage with mandatory name field empty
 | 
			
		||||
    CreateStorageService create = create(test).withName(TestUtils.LONG_ENTITY_NAME);
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name size must be between 1 and 64]");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -55,25 +55,25 @@ public class StorageServiceResourceTest extends EntityResourceTest<StorageServic
 | 
			
		||||
    // Create storage with mandatory name field empty
 | 
			
		||||
    CreateStorageService create = create(test).withName("");
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, BAD_REQUEST, "[name size must be between 1 and 64]");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void post_ServiceAlreadyExists_409(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    CreateStorageService create = create(test);
 | 
			
		||||
    createService(create, adminAuthHeaders());
 | 
			
		||||
    createEntity(create, adminAuthHeaders());
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            createService(create, adminAuthHeaders()));
 | 
			
		||||
            createEntity(create, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, CONFLICT, CatalogExceptionMessage.ENTITY_ALREADY_EXISTS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void post_validService_as_admin_200_ok(TestInfo test) throws HttpResponseException {
 | 
			
		||||
  public void post_validService_as_admin_200_ok(TestInfo test) throws IOException {
 | 
			
		||||
    // Create storage service with different optional fields
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    createAndCheckService(create(test, 1).withDescription(null), authHeaders);
 | 
			
		||||
    createAndCheckService(create(test, 2).withDescription("description"), authHeaders);
 | 
			
		||||
    createAndCheckEntity(create(test, 1).withDescription(null), authHeaders);
 | 
			
		||||
    createAndCheckEntity(create(test, 2).withDescription("description"), authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
@ -82,33 +82,27 @@ public class StorageServiceResourceTest extends EntityResourceTest<StorageServic
 | 
			
		||||
    Map<String, String> 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");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void put_updateStorageService_as_admin_2xx(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    StorageService dbService = createAndCheckService(create(test).withDescription(null), adminAuthHeaders());
 | 
			
		||||
    String id = dbService.getId().toString();
 | 
			
		||||
  public void put_updateStorageService_as_admin_2xx(TestInfo test) throws IOException {
 | 
			
		||||
    createAndCheckEntity(create(test).withDescription(null), adminAuthHeaders());
 | 
			
		||||
 | 
			
		||||
    // Update storage description and ingestion service that are null
 | 
			
		||||
    CreateStorageService update = create(test).withDescription("description1");
 | 
			
		||||
    updateAndCheckService(update, OK, adminAuthHeaders());
 | 
			
		||||
 | 
			
		||||
    // Update description and ingestion schedule again
 | 
			
		||||
    update.withDescription("description1");
 | 
			
		||||
    updateAndCheckService(update, OK, adminAuthHeaders());
 | 
			
		||||
    // TODO add more tests for different fields
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void put_update_as_non_admin_401(TestInfo test) throws HttpResponseException {
 | 
			
		||||
  public void put_update_as_non_admin_401(TestInfo test) throws IOException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    StorageService dbService = createAndCheckService(create(test).withDescription(null), authHeaders);
 | 
			
		||||
    createAndCheckEntity(create(test).withDescription(null), authHeaders);
 | 
			
		||||
 | 
			
		||||
    // Update storage 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");
 | 
			
		||||
  }
 | 
			
		||||
@ -116,7 +110,7 @@ public class StorageServiceResourceTest extends EntityResourceTest<StorageServic
 | 
			
		||||
  @Test
 | 
			
		||||
  public void get_nonExistentStorageService_404_notFound() {
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            getService(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
            getEntity(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND, CatalogExceptionMessage.entityNotFound(Entity.STORAGE_SERVICE,
 | 
			
		||||
            TestUtils.NON_EXISTENT_ENTITY));
 | 
			
		||||
  }
 | 
			
		||||
@ -132,14 +126,14 @@ public class StorageServiceResourceTest extends EntityResourceTest<StorageServic
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_ExistentService_as_admin_200(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    StorageService storageService = createService(create(test), authHeaders);
 | 
			
		||||
    StorageService storageService = createEntity(create(test), authHeaders);
 | 
			
		||||
    deleteService(storageService.getId(), storageService.getName(), authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_as_user_401(TestInfo test) throws HttpResponseException {
 | 
			
		||||
    Map<String, String> authHeaders = adminAuthHeaders();
 | 
			
		||||
    StorageService storageService = createService(create(test), authHeaders);
 | 
			
		||||
    StorageService storageService = createEntity(create(test), authHeaders);
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            deleteService(storageService.getId(), storageService.getName(),
 | 
			
		||||
                    authHeaders("test@open-metadata.org")));
 | 
			
		||||
@ -150,7 +144,7 @@ public class StorageServiceResourceTest extends EntityResourceTest<StorageServic
 | 
			
		||||
  @Test
 | 
			
		||||
  public void delete_notExistentStorageService() {
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
 | 
			
		||||
            getService(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
            getEntity(TestUtils.NON_EXISTENT_ENTITY, adminAuthHeaders()));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND,
 | 
			
		||||
            CatalogExceptionMessage.entityNotFound(Entity.STORAGE_SERVICE, TestUtils.NON_EXISTENT_ENTITY));
 | 
			
		||||
  }
 | 
			
		||||
@ -172,45 +166,6 @@ public class StorageServiceResourceTest extends EntityResourceTest<StorageServic
 | 
			
		||||
    return String.format("storageSvc_%d_%s", index, test.getDisplayName());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static StorageService createService(CreateStorageService create,
 | 
			
		||||
                                             Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    return TestUtils.post(CatalogApplicationTest.getResource("services/storageServices"),
 | 
			
		||||
            create, StorageService.class, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static StorageService createAndCheckService(CreateStorageService create,
 | 
			
		||||
                                                     Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    StorageService service = createService(create, authHeaders);
 | 
			
		||||
    validateService(service, create.getName(), create.getDescription());
 | 
			
		||||
 | 
			
		||||
    // GET the newly created service and validate
 | 
			
		||||
    StorageService getService = getService(service.getId(), authHeaders);
 | 
			
		||||
    validateService(getService, create.getName(), create.getDescription());
 | 
			
		||||
 | 
			
		||||
    // GET the newly created service by name and validate
 | 
			
		||||
    getService = getServiceByName(service.getName(), null, authHeaders);
 | 
			
		||||
    validateService(getService, create.getName(), create.getDescription());
 | 
			
		||||
    return service;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void validateService(StorageService service, String expectedName, String expectedDescription) {
 | 
			
		||||
    assertNotNull(service.getId());
 | 
			
		||||
    assertNotNull(service.getHref());
 | 
			
		||||
    assertEquals(expectedName, service.getName());
 | 
			
		||||
    assertEquals(expectedDescription, service.getDescription());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static StorageService getService(UUID id, Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    return getService(id, null, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static StorageService getService(UUID id, String fields, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    WebTarget target = CatalogApplicationTest.getResource("services/storageServices/" + id);
 | 
			
		||||
    target = fields != null ? target.queryParam("fields", fields) : target;
 | 
			
		||||
    return TestUtils.get(target, StorageService.class, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static StorageService getServiceByName(String name, String fields, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    WebTarget target = CatalogApplicationTest.getResource("services/storageServices/name/" + name);
 | 
			
		||||
@ -218,32 +173,11 @@ public class StorageServiceResourceTest extends EntityResourceTest<StorageServic
 | 
			
		||||
    return TestUtils.get(target, StorageService.class, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static StorageService updateStorageService(CreateStorageService updated,
 | 
			
		||||
                                                    Response.Status status, Map<String, String> authHeaders)
 | 
			
		||||
          throws HttpResponseException {
 | 
			
		||||
    return TestUtils.put(CatalogApplicationTest.getResource("services/storageServices"), updated,
 | 
			
		||||
            StorageService.class, status, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static void updateAndCheckService(CreateStorageService update, Response.Status status,
 | 
			
		||||
                                           Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    StorageService service = updateStorageService(update, status, authHeaders);
 | 
			
		||||
    validateService(service, service.getName(), update.getDescription());
 | 
			
		||||
 | 
			
		||||
    // GET the newly updated storage and validate
 | 
			
		||||
    StorageService getService = getService(service.getId(), authHeaders);
 | 
			
		||||
    validateService(getService, service.getName(), update.getDescription());
 | 
			
		||||
 | 
			
		||||
    // GET the newly updated storage by name and validate
 | 
			
		||||
    getService = getServiceByName(service.getName(), null, authHeaders);
 | 
			
		||||
    validateService(getService, service.getName(), update.getDescription());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void deleteService(UUID id, String name, Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    TestUtils.delete(CatalogApplicationTest.getResource("services/storageServices/" + id), authHeaders);
 | 
			
		||||
 | 
			
		||||
    // Ensure deleted service does not exist
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () -> getService(id, authHeaders));
 | 
			
		||||
    HttpResponseException exception = assertThrows(HttpResponseException.class, () -> getEntity(id, authHeaders));
 | 
			
		||||
    TestUtils.assertResponse(exception, NOT_FOUND,
 | 
			
		||||
            CatalogExceptionMessage.entityNotFound(Entity.STORAGE_SERVICE, id));
 | 
			
		||||
 | 
			
		||||
@ -260,18 +194,21 @@ public class StorageServiceResourceTest extends EntityResourceTest<StorageServic
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void validateCreatedEntity(StorageService createdEntity, Object request, Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
 | 
			
		||||
  public void validateCreatedEntity(StorageService service, Object request, Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    CreateStorageService createRequest = (CreateStorageService) request;
 | 
			
		||||
    validateCommonEntityFields(getEntityInterface(service), createRequest.getDescription(),
 | 
			
		||||
            getPrincipal(authHeaders), null);
 | 
			
		||||
    assertEquals(createRequest.getName(), service.getName());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void validateUpdatedEntity(StorageService updatedEntity, Object request, Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
 | 
			
		||||
  public void validateUpdatedEntity(StorageService service, Object request, Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
    validateCreatedEntity(service, request, authHeaders);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void compareEntities(StorageService expected, StorageService updated, Map<String, String> authHeaders) throws HttpResponseException {
 | 
			
		||||
 | 
			
		||||
    // PATCH operation is not supported by this entity
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
@ -281,6 +218,6 @@ public class StorageServiceResourceTest extends EntityResourceTest<StorageServic
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void assertFieldChange(String fieldName, Object expected, Object actual) throws IOException {
 | 
			
		||||
 | 
			
		||||
    super.assertCommonFieldChange(fieldName, expected, actual);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user