@Transactional
  @ApolloAuditLog(type = OpType.DELETE, name = "App.delete")
  public App deleteAppInLocal(String appId) {
    App managedApp = appRepository.findByAppId(appId);
    if (managedApp == null) {
      throw BadRequestException.appNotExists(appId);
    }
    String operator = userInfoHolder.getUser().getUserId();

    //this operator is passed to com.ctrip.framework.apollo.portal.listener.DeletionListener.onAppDeletionEvent
    managedApp.setDataChangeLastModifiedBy(operator);

    //删除portal数据库中的app
    appRepository.deleteApp(appId, operator);

    // append a deleted data influence should be bounded
    apolloAuditLogApi.appendDataInfluences(Collections.singletonList(managedApp), App.class);

    //删除portal数据库中的appNamespace
    appNamespaceService.batchDeleteByAppId(appId, operator);

    //删除portal数据库中的收藏表
    favoriteService.batchDeleteByAppId(appId, operator);

    //删除portal数据库中Permission、Role相关数据
    rolePermissionService.deleteRolePermissionsByAppId(appId, operator);

    return managedApp;
  }
@Test
  void testDeleteAppInLocal() {
    final String appId = "appId100";
    {
      App app = new App();
      app.setAppId(appId);
      Mockito.when(appRepository.findByAppId(Mockito.eq(appId)))
          .thenReturn(app);
    }
    {
      Mockito.when(appRepository.deleteApp(Mockito.eq(appId), Mockito.eq(OPERATOR_USER_ID)))
          .thenReturn(1);
    }

    App deletedApp = appService.deleteAppInLocal(appId);
    Mockito.verify(appRepository, Mockito.times(1))
        .deleteApp(Mockito.eq(appId), Mockito.eq(OPERATOR_USER_ID));
    Mockito.verify(userInfoHolder, Mockito.times(1))
        .getUser();
    Mockito.verify(apolloAuditLogApi, Mockito.times(1))
        .appendDataInfluences(Mockito.eq(Collections.singletonList(deletedApp)), Mockito.eq(App.class));
    Mockito.verify(appNamespaceService, Mockito.times(1))
        .batchDeleteByAppId(Mockito.eq(appId), Mockito.eq(OPERATOR_USER_ID));
    Mockito.verify(favoriteService, Mockito.times(1))
        .batchDeleteByAppId(Mockito.eq(appId), Mockito.eq(OPERATOR_USER_ID));
    Mockito.verify(rolePermissionService, Mockito.times(1))
        .deleteRolePermissionsByAppId(Mockito.eq(appId), Mockito.eq(OPERATOR_USER_ID));

    assertEquals(OPERATOR_USER_ID, deletedApp.getDataChangeLastModifiedBy());
  }