void dropEntity()

in polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java [727:940]


  void dropEntity(List<PolarisEntityCore> catalogPath, PolarisBaseEntity entityToDrop) {
    // see if the entity exists
    final boolean exists;
    boolean hasChildren = false;

    // check if it exists
    PolarisBaseEntity entity =
        polarisMetaStoreManager
            .loadEntity(
                this.polarisCallContext,
                entityToDrop.getCatalogId(),
                entityToDrop.getId(),
                entityToDrop.getType())
            .getEntity();
    if (entity != null) {
      EntityResult entityFound =
          polarisMetaStoreManager.readEntityByName(
              this.polarisCallContext,
              catalogPath,
              entity.getType(),
              entity.getSubType(),
              entity.getName());
      exists = entityFound.isSuccess();

      // if exists, see if empty
      if (exists
          && (entity.getType() == PolarisEntityType.CATALOG
              || entity.getType() == PolarisEntityType.NAMESPACE)) {
        // build path
        List<PolarisEntityCore> path = new ArrayList<>();
        if (catalogPath != null) {
          path.addAll(catalogPath);
        }
        path.add(entityToDrop);

        // get all children, cannot be null
        List<EntityNameLookupRecord> children =
            polarisMetaStoreManager
                .listEntities(
                    this.polarisCallContext,
                    path,
                    PolarisEntityType.NAMESPACE,
                    PolarisEntitySubType.NULL_SUBTYPE)
                .getEntities();
        Assertions.assertThat(children).isNotNull();
        if (children.isEmpty() && entity.getType() == PolarisEntityType.NAMESPACE) {
          children =
              polarisMetaStoreManager
                  .listEntities(
                      this.polarisCallContext,
                      path,
                      PolarisEntityType.TABLE_LIKE,
                      PolarisEntitySubType.ANY_SUBTYPE)
                  .getEntities();
          Assertions.assertThat(children).isNotNull();
        } else if (children.isEmpty()) {
          children =
              polarisMetaStoreManager
                  .listEntities(
                      this.polarisCallContext,
                      path,
                      PolarisEntityType.CATALOG_ROLE,
                      PolarisEntitySubType.ANY_SUBTYPE)
                  .getEntities();
          Assertions.assertThat(children).isNotNull();
          // if only one left, it can be dropped.
          if (children.size() == 1) {
            children.clear();
          }
        }
        hasChildren = !children.isEmpty();
      }
    } else {
      exists = false;
    }

    // load all the grants to ensure they are properly cleaned
    final List<PolarisBaseEntity> granteeEntities;
    final List<PolarisBaseEntity> securableEntities;
    if (exists) {
      granteeEntities =
          new ArrayList<>(
              polarisMetaStoreManager
                  .loadGrantsOnSecurable(this.polarisCallContext, entity)
                  .getEntities());
      securableEntities =
          new ArrayList<>(
              polarisMetaStoreManager
                  .loadGrantsToGrantee(this.polarisCallContext, entity)
                  .getEntities());
    } else {
      granteeEntities = List.of();
      securableEntities = List.of();
    }

    // now drop it
    Map<String, String> cleanupProperties =
        Map.of("taskId", String.valueOf(entity.getId()), "cleanupProperty", "cleanupValue");
    DropEntityResult dropResult =
        polarisMetaStoreManager.dropEntityIfExists(
            this.polarisCallContext, catalogPath, entityToDrop, cleanupProperties, true);

    // should have been dropped if exists
    if (entityToDrop.cannotBeDroppedOrRenamed()) {
      Assertions.assertThat(dropResult.isSuccess()).isFalse();
      Assertions.assertThat(dropResult.failedBecauseNotEmpty()).isFalse();
      Assertions.assertThat(dropResult.isEntityUnDroppable()).isTrue();
    } else if (exists && hasChildren) {
      Assertions.assertThat(dropResult.isSuccess()).isFalse();
      Assertions.assertThat(dropResult.failedBecauseNotEmpty()).isTrue();
      Assertions.assertThat(dropResult.isEntityUnDroppable()).isFalse();
    } else if (entityToDrop.getType() == PolarisEntityType.POLICY) {
      // When dropping policy with cleanup = true, we do not need cleanup task
      Assertions.assertThat(dropResult.isSuccess()).isEqualTo(exists);
      Assertions.assertThat(dropResult.failedBecauseNotEmpty()).isFalse();
      Assertions.assertThat(dropResult.isEntityUnDroppable()).isFalse();
      Assertions.assertThat(dropResult.getCleanupTaskId()).isNull();
    } else {
      Assertions.assertThat(dropResult.isSuccess()).isEqualTo(exists);
      Assertions.assertThat(dropResult.failedBecauseNotEmpty()).isFalse();
      Assertions.assertThat(dropResult.isEntityUnDroppable()).isFalse();
      Assertions.assertThat(dropResult.getCleanupTaskId()).isNotNull();
      PolarisBaseEntity cleanupTask =
          polarisMetaStoreManager
              .loadEntity(
                  this.polarisCallContext,
                  0L,
                  dropResult.getCleanupTaskId(),
                  PolarisEntityType.TASK)
              .getEntity();
      Assertions.assertThat(cleanupTask).isNotNull();
      Assertions.assertThat(cleanupTask.getType()).isEqualTo(PolarisEntityType.TASK);
      Assertions.assertThat(cleanupTask.getInternalProperties()).isNotNull();
      Map<String, String> internalProperties =
          PolarisObjectMapperUtil.deserializeProperties(
              polarisCallContext, cleanupTask.getInternalProperties());
      Assertions.assertThat(internalProperties).isEqualTo(cleanupProperties);
      Map<String, String> properties =
          PolarisObjectMapperUtil.deserializeProperties(
              polarisCallContext, cleanupTask.getProperties());
      Assertions.assertThat(properties).isNotNull();
      Assertions.assertThat(properties.get(PolarisTaskConstants.TASK_DATA)).isNotNull();
      PolarisBaseEntity droppedEntity =
          PolarisObjectMapperUtil.deserialize(
              polarisCallContext,
              properties.get(PolarisTaskConstants.TASK_DATA),
              PolarisBaseEntity.class);
      Assertions.assertThat(droppedEntity).isNotNull();
      Assertions.assertThat(droppedEntity.getId()).isEqualTo(entity.getId());
    }

    // verify gone if it was dropped
    if (dropResult.isSuccess()) {
      // should be found but deleted
      PolarisBaseEntity entityAfterDrop =
          polarisMetaStoreManager
              .loadEntity(
                  this.polarisCallContext,
                  entityToDrop.getCatalogId(),
                  entityToDrop.getId(),
                  entityToDrop.getType())
              .getEntity();

      // ensure dropped
      Assertions.assertThat(entityAfterDrop).isNull();

      // should no longer exists
      Assertions.assertThat(entity).isNotNull();
      EntityResult entityFound =
          polarisMetaStoreManager.readEntityByName(
              this.polarisCallContext,
              catalogPath,
              entity.getType(),
              entity.getSubType(),
              entity.getName());

      // should not be found
      Assertions.assertThat(entityFound.getReturnStatus())
          .isEqualTo(BaseResult.ReturnStatus.ENTITY_NOT_FOUND);

      // make sure that the entity which was dropped is no longer referenced by a grant with any
      // of the entity it was connected with before being dropped
      for (PolarisBaseEntity connectedEntity : granteeEntities) {
        LoadGrantsResult grantResult =
            polarisMetaStoreManager.loadGrantsToGrantee(this.polarisCallContext, connectedEntity);
        if (grantResult.isSuccess()) {
          long cnt =
              grantResult.getGrantRecords().stream()
                  .filter(gr -> gr.getSecurableId() == entityToDrop.getId())
                  .count();
          Assertions.assertThat(cnt).isZero();
        } else {
          // special case when a catalog is dropped, the catalog_admin role is also dropped with it
          Assertions.assertThat(
                  grantResult.getReturnStatus() == BaseResult.ReturnStatus.ENTITY_NOT_FOUND
                      && entityToDrop.getType() == PolarisEntityType.CATALOG
                      && connectedEntity.getType() == PolarisEntityType.CATALOG_ROLE
                      && connectedEntity
                          .getName()
                          .equals(PolarisEntityConstants.getNameOfCatalogAdminRole()))
              .isTrue();
        }
      }
      for (PolarisBaseEntity connectedEntity : securableEntities) {
        LoadGrantsResult grantResult =
            polarisMetaStoreManager.loadGrantsOnSecurable(this.polarisCallContext, connectedEntity);
        long cnt =
            grantResult.getGrantRecords().stream()
                .filter(gr -> gr.getGranteeId() == entityToDrop.getId())
                .count();
        Assertions.assertThat(cnt).isZero();
      }
    }
  }