diff --git a/src/main/java/com/michelin/ns4kafka/controller/quota/ResourceQuotaController.java b/src/main/java/com/michelin/ns4kafka/controller/quota/ResourceQuotaController.java index 8f8957d8..25a3a707 100644 --- a/src/main/java/com/michelin/ns4kafka/controller/quota/ResourceQuotaController.java +++ b/src/main/java/com/michelin/ns4kafka/controller/quota/ResourceQuotaController.java @@ -42,6 +42,7 @@ public class ResourceQuotaController extends NamespacedResourceController { * List quotas by namespace. * * @param namespace The namespace + * @param name The name parameter * @return A list of quotas */ @Get @@ -59,7 +60,7 @@ public List list(String namespace, @QueryValue(defaultVal * @param namespace The name * @param quota The quota name * @return A quota - * @deprecated use list(String, String name) instead. + * @deprecated use {@link #list(String, String)} instead. */ @Get("/{quota}") @Deprecated(since = "1.12.0") @@ -115,16 +116,55 @@ public HttpResponse apply(String namespace, @Body @Valid Resource return formatHttpResponse(resourceQuotaService.create(quota), status); } + /** + * Delete quotas. + * + * @param namespace The namespace + * @param name The name parameter + * @param dryrun Is dry run mode or not? + * @return An HTTP response + */ + @Delete + @Status(HttpStatus.NO_CONTENT) + public HttpResponse bulkDelete(String namespace, @QueryValue(defaultValue = "*") String name, + @QueryValue(defaultValue = "false") boolean dryrun) { + + List resourceQuotas = resourceQuotaService.findByWildcardName(namespace, name); + + if (resourceQuotas.isEmpty()) { + return HttpResponse.notFound(); + } + + if (dryrun) { + return HttpResponse.noContent(); + } + + resourceQuotas.forEach(resourceQuota -> { + sendEventLog( + resourceQuota, + ApplyStatus.deleted, + resourceQuota.getSpec(), + null, + EMPTY_STRING + ); + resourceQuotaService.delete(resourceQuota); + }); + + return HttpResponse.noContent(); + } + /** * Delete a quota. * * @param namespace The namespace * @param name The resource quota - * @param dryrun Is dry run mode or not ? + * @param dryrun Is dry run mode or not? * @return An HTTP response + * @deprecated use {@link #bulkDelete(String, String, boolean)} instead. */ @Delete("/{name}{?dryrun}") @Status(HttpStatus.NO_CONTENT) + @Deprecated(since = "1.13.0") public HttpResponse delete(String namespace, String name, @QueryValue(defaultValue = "false") boolean dryrun) { Optional resourceQuota = resourceQuotaService.findByName(namespace, name); diff --git a/src/test/java/com/michelin/ns4kafka/controller/ResourceQuotaControllerTest.java b/src/test/java/com/michelin/ns4kafka/controller/ResourceQuotaControllerTest.java index ed161303..ad426b39 100644 --- a/src/test/java/com/michelin/ns4kafka/controller/ResourceQuotaControllerTest.java +++ b/src/test/java/com/michelin/ns4kafka/controller/ResourceQuotaControllerTest.java @@ -321,7 +321,8 @@ void shouldApplyUpdated() { } @Test - void shouldDeleteWhenNotFound() { + @SuppressWarnings("deprecation") + void shouldNotDeleteQuotaWhenNotFound() { when(resourceQuotaService.findByName("test", "quota")).thenReturn(Optional.empty()); HttpResponse actual = resourceQuotaController.delete("test", "quota", false); assertEquals(HttpStatus.NOT_FOUND, actual.getStatus()); @@ -329,11 +330,12 @@ void shouldDeleteWhenNotFound() { } @Test - void shouldDeleteWhenDryRun() { + @SuppressWarnings("deprecation") + void shouldNotDeleteQuotaWhenDryRun() { ResourceQuota resourceQuota = ResourceQuota.builder() .metadata(Metadata.builder() .cluster("local") - .name("created-quota") + .name("quota") .build()) .spec(Map.of("count/topics", "3")) .build(); @@ -345,11 +347,12 @@ void shouldDeleteWhenDryRun() { } @Test - void shouldDelete() { + @SuppressWarnings("deprecation") + void shouldDeleteQuota() { ResourceQuota resourceQuota = ResourceQuota.builder() .metadata(Metadata.builder() .cluster("local") - .name("created-quota") + .name("quota") .build()) .spec(Map.of("count/topics", "3")) .build(); @@ -364,4 +367,49 @@ void shouldDelete() { assertEquals(HttpStatus.NO_CONTENT, actual.getStatus()); verify(resourceQuotaService).delete(resourceQuota); } + + @Test + void shouldNotBulkDeleteQuotaWhenNotFound() { + when(resourceQuotaService.findByWildcardName("test", "quota*")).thenReturn(List.of()); + HttpResponse actual = resourceQuotaController.bulkDelete("test", "quota*", false); + assertEquals(HttpStatus.NOT_FOUND, actual.getStatus()); + verify(resourceQuotaService, never()).delete(ArgumentMatchers.any()); + } + + @Test + void shouldNotBulkDeleteQuotaWhenDryRun() { + ResourceQuota resourceQuota1 = ResourceQuota.builder() + .metadata(Metadata.builder() + .cluster("local") + .name("quota1") + .build()) + .spec(Map.of("count/topics", "3")) + .build(); + + when(resourceQuotaService.findByWildcardName("test", "quota*")).thenReturn(List.of(resourceQuota1)); + HttpResponse actual = resourceQuotaController.bulkDelete("test", "quota*", true); + assertEquals(HttpStatus.NO_CONTENT, actual.getStatus()); + verify(resourceQuotaService, never()).delete(ArgumentMatchers.any()); + } + + @Test + void shouldBulkDeleteQuota() { + ResourceQuota resourceQuota = ResourceQuota.builder() + .metadata(Metadata.builder() + .cluster("local") + .name("quota") + .build()) + .spec(Map.of("count/topics", "3")) + .build(); + + when(resourceQuotaService.findByWildcardName("test", "quota*")).thenReturn(List.of(resourceQuota)); + when(securityService.username()).thenReturn(Optional.of("test-user")); + when(securityService.hasRole(ResourceBasedSecurityRule.IS_ADMIN)).thenReturn(false); + doNothing().when(applicationEventPublisher).publishEvent(any()); + doNothing().when(resourceQuotaService).delete(resourceQuota); + + HttpResponse actual = resourceQuotaController.bulkDelete("test", "quota*", false); + assertEquals(HttpStatus.NO_CONTENT, actual.getStatus()); + verify(resourceQuotaService).delete(resourceQuota); + } }