diff --git a/application/src/test/java/org/thingsboard/server/controller/AiModelControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AiModelControllerTest.java index 1a6ece29f3..22850520c1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AiModelControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AiModelControllerTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.controller; +import com.datastax.oss.driver.api.core.uuid.Uuids; import org.junit.Test; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.test.web.servlet.ResultActions; @@ -23,6 +24,7 @@ import org.thingsboard.server.common.data.ai.AiModel; import org.thingsboard.server.common.data.ai.model.chat.OpenAiChatModelConfig; import org.thingsboard.server.common.data.ai.provider.OpenAiProviderConfig; import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.id.AiModelId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.service.entitiy.TbLogEntityActionService; @@ -32,9 +34,12 @@ import java.util.Objects; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -119,7 +124,7 @@ public class AiModelControllerTest extends AbstractControllerTest { } @Test - public void saveAiModel_whenUpdatingExistingModelAsTenantAdmin_shouldSucceedAndLogAction() throws Exception { + public void saveAiModel_whenUpdatingExistingModelAsTenantAdmin_shouldSucceed() throws Exception { // GIVEN loginTenantAdmin(); @@ -169,6 +174,85 @@ public class AiModelControllerTest extends AbstractControllerTest { ); } + /* --- Delete API tests --- */ + + @Test + public void deleteAiModelById_whenUserIsSysAdmin_shouldReturnForbidden() throws Exception { + // GIVEN + loginSysAdmin(); + + // WHEN + ResultActions result = doDelete("/api/ai/model/" + Uuids.timeBased()); + + // THEN + result.andExpect(status().isForbidden()).andExpect(statusReason(equalTo(msgErrorPermission))); + } + + @Test + public void deleteAiModelById_whenUserIsCustomerUser_shouldReturnForbidden() throws Exception { + // GIVEN + loginCustomerUser(); + + // WHEN + ResultActions result = doDelete("/api/ai/model/" + Uuids.timeBased()); + + // THEN + result.andExpect(status().isForbidden()).andExpect(statusReason(equalTo(msgErrorPermission))); + } + + @Test + public void deleteAiModelById_whenDeletingExistingModelAsTenantAdmin_shouldSucceedAndReturnTrue() throws Exception { + // GIVEN + loginTenantAdmin(); + + var model = doPost("/api/ai/model", constructValidModel(), AiModel.class); + + // WHEN + boolean deleted = doDelete("/api/ai/model/" + model.getId(), Boolean.class); + + // THEN + assertThat(deleted).isTrue(); + + // verify a rule engine message was sent, and an audit log was created + then(logEntityActionService).should().logEntityAction( + eq(tenantId), + eq(model.getId()), + eq(model), + eq(ActionType.DELETED), + argThat(actualUser -> Objects.equals(actualUser.getId(), tenantAdminUser.getId())), + eq(model.getId().toString()) + ); + + // verify model cannot be found anymore + doGet("/api/ai/model/" + model.getId()) + .andExpect(status().isNotFound()) + .andExpect(statusReason(is("AI model with id [" + model.getId() + "] is not found"))); + } + + @Test + public void deleteAiModelById_whenDeletingNonexistentModelAsTenantAdmin_shouldSucceedAndReturnFalse() throws Exception { + // GIVEN + loginTenantAdmin(); + + var nonexistentModelId = new AiModelId(Uuids.timeBased()); + + // WHEN + boolean deleted = doDelete("/api/ai/model/" + nonexistentModelId, Boolean.class); + + // THEN + assertThat(deleted).isFalse(); + + // verify a rule engine message was not sent, and an audit log was not created + then(logEntityActionService).should(never()).logEntityAction( + eq(tenantId), + eq(nonexistentModelId), + any(AiModel.class), + eq(ActionType.DELETED), + argThat(actualUser -> Objects.equals(actualUser.getId(), tenantAdminUser.getId())), + eq(nonexistentModelId.toString()) + ); + } + private AiModel constructValidModel() { var modelConfig = OpenAiChatModelConfig.builder() .providerConfig(new OpenAiProviderConfig("test-api-key"))