content: package io.aiven.klaw.helpers.db.rdbms;
  
  import static org.assertj.core.api.Assertions.assertThat;
  import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
  import static org.mockito.ArgumentMatchers.*;
  import static org.mockito.Mockito.times;
  import static org.mockito.Mockito.verify;
  import static org.mockito.Mockito.when;
  
  import io.aiven.klaw.UtilMethods;
  import io.aiven.klaw.dao.CRUDResponse;
  import io.aiven.klaw.dao.Env;
  import io.aiven.klaw.dao.EnvTag;
  import io.aiven.klaw.dao.KwKafkaConnector;
  import io.aiven.klaw.dao.RegisterUserInfo;
  import io.aiven.klaw.dao.Topic;
  import io.aiven.klaw.dao.TopicRequest;
  import io.aiven.klaw.dao.UserInfo;
  import io.aiven.klaw.error.KlawNotAuthorizedException;
  import io.aiven.klaw.model.enums.ApiResultStatus;
  import io.aiven.klaw.model.enums.NewUserStatus;
  import io.aiven.klaw.repository.AclRequestsRepo;
  import io.aiven.klaw.repository.KwKafkaConnectorRepo;
  import io.aiven.klaw.repository.MessageSchemaRepo;
  import io.aiven.klaw.repository.RegisterInfoRepo;
  import io.aiven.klaw.repository.SchemaRequestRepo;
  import io.aiven.klaw.repository.TopicRepo;
  import io.aiven.klaw.repository.TopicRequestsRepo;
  import io.aiven.klaw.repository.UserInfoRepo;
  import java.sql.Timestamp;
  import java.time.Instant;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Optional;
  import java.util.UUID;
  import java.util.stream.Stream;
  import org.junit.jupiter.api.BeforeEach;
  import org.junit.jupiter.api.Test;
  import org.junit.jupiter.api.extension.ExtendWith;
  import org.junit.jupiter.params.ParameterizedTest;
  import org.junit.jupiter.params.provider.Arguments;
  import org.junit.jupiter.params.provider.MethodSource;
  import org.junit.jupiter.params.provider.ValueSource;
  import org.mockito.ArgumentCaptor;
  import org.mockito.Captor;
  import org.mockito.Mock;
  import org.springframework.test.context.junit.jupiter.SpringExtension;
  import org.springframework.test.util.ReflectionTestUtils;
  
  @ExtendWith(SpringExtension.class)
  public class UpdateDataJdbcTest {
  
    public static final int TOKEN_TTL = 60000;
    @Mock private TopicRequestsRepo topicRequestsRepo;
  
    @Mock private KwKafkaConnectorRepo kafkaConnectorRepo;
  
    @Mock private AclRequestsRepo aclRequestsRepo;
  
    @Mock private UserInfoRepo userInfoRepo;
  
    @Mock private RegisterInfoRepo registerInfoRepo;
  
    @Mock private SchemaRequestRepo schemaRequestRepo;
  
    @Mock private InsertDataJdbc insertDataJdbcHelper;
    @Mock private TopicRepo topicRepo;
  
    @Mock MessageSchemaRepo messageSchemaRepo;
  
    @Mock private DeleteDataJdbc deleteDataJdbcHelper;
  
    @Mock private SelectDataJdbc selectDataJdbcHelper;
  
    @Mock private Env kafkaEnv;
  
    private UpdateDataJdbc updateData;
  
    private UtilMethods utilMethods;
  
    @Captor private ArgumentCaptor<UserInfo> userCaptor;
  
    @Mock UserInfo userInfo;
  
    @BeforeEach
    public void setUp() throws Exception {
      updateData =
          new UpdateDataJdbc(
              topicRequestsRepo,
              aclRequestsRepo,
              userInfoRepo,
              schemaRequestRepo,
              insertDataJdbcHelper,
              selectDataJdbcHelper,
              registerInfoRepo);
      utilMethods = new UtilMethods();
      ReflectionTestUtils.setField(updateData, "deleteDataJdbcHelper", deleteDataJdbcHelper);
      ReflectionTestUtils.setField(updateData, "selectDataJdbcHelper", selectDataJdbcHelper);
      ReflectionTestUtils.setField(updateData, "topicRepo", topicRepo);
      ReflectionTestUtils.setField(updateData, "kafkaConnectorRepo", kafkaConnectorRepo);
      ReflectionTestUtils.setField(updateData, "messageSchemaRepo", messageSchemaRepo);
      ReflectionTestUtils.setField(updateData, "tokenTTL", TOKEN_TTL);
    }
  
    @Test
    public void declineTopicRequest() {
      String result = updateData.declineTopicRequest(utilMethods.getTopicRequest(1001), "uiuser2");
      assertThat(result).isEqualTo(ApiResultStatus.SUCCESS.value);
    }
  
    // parameters from RequestOperationType
    @Test
    public void updateUpdateTopicRequest() {
      int reqNum = 1001;
      String requestOperationType = "Update";
      when(insertDataJdbcHelper.insertIntoTopicSOT(any()))
          .thenReturn(
              CRUDResponse.<Topic>builder().resultStatus(ApiResultStatus.SUCCESS.value).build());
      when(insertDataJdbcHelper.getNextTopicRequestId(anyString(), anyInt())).thenReturn(reqNum);
      TopicRequest req = utilMethods.getTopicRequest(1001);
      req.setOtherParams("1001");
      req.setRequestOperationType(requestOperationType);
      CRUDResponse<Topic> result = updateData.updateTopicRequest(req, "uiuser2");
      assertThat(result.getResultStatus()).isEqualTo(ApiResultStatus.SUCCESS.value);
      verify(topicRepo, times(1)).save(any());
    }
  
    @Test
    public void updateDeleteTopicRequest() {
      int reqNum = 1001;
      String requestOperationType = "Delete";
      when(insertDataJdbcHelper.insertIntoTopicSOT(any()))
          .thenReturn(
              CRUDResponse.<Topic>builder().resultStatus(ApiResultStatus.SUCCESS.value).build());
      when(insertDataJdbcHelper.getNextTopicRequestId(anyString(), anyInt())).thenReturn(reqNum);
      when(selectDataJdbcHelper.selectEnvDetails(anyString(), anyInt())).thenReturn(kafkaEnv);
      EnvTag envTag = new EnvTag();
      envTag.setId("3");
      when(kafkaEnv.getAssociatedEnv()).thenReturn(envTag);
      when(deleteDataJdbcHelper.deleteTopics(any(Topic.class)))
          .thenReturn(
              CRUDResponse.<Topic>builder().resultStatus(ApiResultStatus.SUCCESS.value).build());
      TopicRequest req = utilMethods.getTopicRequest(1001);
  
      req.setRequestOperationType(requestOperationType);
      req.setDeleteAssociatedSchema(true);
      CRUDResponse<Topic> result = updateData.updateTopicRequest(req, "uiuser2");
      assertThat(result.getResultStatus()).isEqualTo(ApiResultStatus.SUCCESS.value);
      verify(deleteDataJdbcHelper, times(1)).deleteTopics(any());
      verify(deleteDataJdbcHelper, times(1))
          .deleteSchemasWithOptions(anyInt(), anyString(), anyString());
    }
  
    @ParameterizedTest
    @ValueSource(strings = {"Create", "Promote"})
    public void updateCreateAndPromoteTopicRequest(String requestOperationType) {
      int reqNum = 1001;
      when(insertDataJdbcHelper.insertIntoTopicSOT(any()))
          .thenReturn(
              CRUDResponse.<Topic>builder().resultStatus(ApiResultStatus.SUCCESS.value).build());
      when(insertDataJdbcHelper.getNextTopicRequestId(anyString(), anyInt())).thenReturn(reqNum);
      TopicRequest req = utilMethods.getTopicRequest(1001);
      req.setRequestOperationType(requestOperationType);
      CRUDResponse<Topic> result = updateData.updateTopicRequest(req, "uiuser2");
      assertThat(result.getResultStatus()).isEqualTo(ApiResultStatus.SUCCESS.value);
      verify(insertDataJdbcHelper, times(1)).insertIntoTopicSOT(any());
    }
  
    @Test
    public void updateAclRequest() {
      when(insertDataJdbcHelper.insertIntoAclsSOT(any(), eq(false)))
          .thenReturn(ApiResultStatus.SUCCESS.value);
      String result =
          updateData.updateAclRequest(
              utilMethods.getAclRequestCreate("testtopic"), "uiuser2", new HashMap<>(), false);
      assertThat(result).isEqualTo(ApiResultStatus.SUCCESS.value);
    }
  
    @Test
    public void updateAclRequest1() {
      when(deleteDataJdbcHelper.deletePrevAclRecs(any())).thenReturn(ApiResultStatus.SUCCESS.value);
      String result =
          updateData.updateAclRequest(
              utilMethods.getAclRequest("testtopic"), "uiuser2", new HashMap<>(), false);
      assertThat(result).isEqualTo(ApiResultStatus.SUCCESS.value);
    }
  
    @Test
    public void declineAclRequest() {
      String result = updateData.declineAclRequest(utilMethods.getAclRequest("testtopic"), "uiuser2");
      assertThat(result).isEqualTo(ApiResultStatus.SUCCESS.value);
    }
  
    @Test
    public void updatePassword() {
      String user = "uiuser1";
      when(userInfoRepo.findById(user)).thenReturn(Optional.of(userInfo));
      String result = updateData.updatePassword(user, "pwd");
      assertThat(result).isEqualTo(ApiResultStatus.SUCCESS.value);
    }
  
    @Test
    public void resetPassword_withSuccess() throws KlawNotAuthorizedException {
      String user = "uiuser1";
      String resetToken = UUID.randomUUID().toString();
      when(userInfo.getResetTokenGeneratedAt()).thenReturn(Timestamp.from(Instant.now()));
      when(userInfo.getResetToken()).thenReturn(resetToken);
      when(userInfoRepo.findById(user)).thenReturn(Optional.of(userInfo));
  
      String result = updateData.resetPassword(user, "newPWD", resetToken);
      assertThat(result).isEqualTo(ApiResultStatus.SUCCESS.value);
    }
  
    @Test
    public void resetPassword_withFailureIncorrectToken() throws KlawNotAuthorizedException {
      String user = "uiuser1";
      String resetToken = UUID.randomUUID().toString();
      when(userInfo.getResetTokenGeneratedAt()).thenReturn(Timestamp.from(Instant.now()));
      when(userInfo.getResetToken()).thenReturn(resetToken);
      when(userInfoRepo.findById(user)).thenReturn(Optional.of(userInfo));
  
      assertThatThrownBy(
              () -> {
                updateData.resetPassword(user, "newPWD", UUID.randomUUID().toString());
              })
          .isInstanceOf(KlawNotAuthorizedException.class)
          .hasMessageContaining(
              "Password for uiuser1 not reset as token was no longer valid or supplied token was invalid.");
    }
  
    @Test
    public void resetPassword_withFailureTokenTimeout() throws KlawNotAuthorizedException {
      String user = "uiuser1";
      String resetToken = UUID.randomUUID().toString();
      Timestamp timestamp = Timestamp.from(Instant.now());
      // reset token timeout is the length of the time to live plus a second old.
      when(userInfo.getResetTokenGeneratedAt())
          .thenReturn(new Timestamp(timestamp.getTime() - (TOKEN_TTL + 1)));
      when(userInfo.getResetToken()).thenReturn(resetToken);
      when(userInfoRepo.findById(user)).thenReturn(Optional.of(userInfo));
  
      assertThatThrownBy(
              () -> {
                updateData.resetPassword(user, "newPWD", resetToken);
              })
          .isInstanceOf(KlawNotAuthorizedException.class)
          .hasMessageContaining(
              "Password for uiuser1 not reset as token was no longer valid or supplied token was invalid.");
    }
  
    @Test
    public void resetPassword_withSucess() throws KlawNotAuthorizedException {
      String user = "uiuser1";
      String resetToken = UUID.randomUUID().toString();
      Timestamp timestamp = Timestamp.from(Instant.now());
      // reset token timeout half the length of the
      when(userInfo.getResetTokenGeneratedAt())
          .thenReturn(new Timestamp(timestamp.getTime() - (TOKEN_TTL / 2)));
      when(userInfo.getResetToken()).thenReturn(resetToken);
      when(userInfoRepo.findById(user)).thenReturn(Optional.of(userInfo));
      String result = updateData.resetPassword(user, "newPWD", resetToken);
  
      assertThat(result).isEqualTo(ApiResultStatus.SUCCESS.value);
    }
  
    @Test
    public void generateToken_withSucess() {
      String user = "uiuser1";
      UserInfo info = new UserInfo();
      info.setTenantId(101);
      info.setRole("User");
      info.setUsername(user);
      when(userInfoRepo.findById(user)).thenReturn(Optional.of(info));
  
      String result = updateData.generatePasswordResetToken(user);
      assertThat(result).isNotEqualTo(ApiResultStatus.FAILURE.value);
      verify(userInfoRepo, times(1)).save(userCaptor.capture());
      UserInfo savedUser = userCaptor.getValue();
      assertThat(savedUser.getResetTokenGeneratedAt()).isEqualToIgnoringSeconds(Instant.now());
      assertThat(savedUser.getResetToken()).isNotNull();
      assertThat(savedUser.getResetToken()).isEqualTo(result);
    }
  
    @Test
    public void generateToken_withFailureNoSuchUser() {
      String user = "uiuser1";
  
      when(userInfoRepo.findById(user)).thenReturn(Optional.empty());
      String result = updateData.generatePasswordResetToken(user);
      assertThat(result).isEqualTo(ApiResultStatus.FAILURE.value);
      verify(userInfoRepo, times(0)).save(any());
    }
  
    @Test
    public void updateSchemaRequest() {
      when(messageSchemaRepo.findAllByTenantIdAndTopicnameAndSchemaversionAndEnvironment(
              anyInt(), anyString(), anyString(), anyString()))
          .thenReturn(Collections.emptyList());
      String result =
          updateData.updateSchemaRequest(utilMethods.getSchemaRequestsDao().get(0), "uiuser1");
      assertThat(result).isEqualTo(ApiResultStatus.SUCCESS.value);
    }
  
    @Test
    public void updateConnectorDocumentation() {
      KwKafkaConnector kwKafkaConnector = utilMethods.getKwKafkaConnector();
      when(kafkaConnectorRepo.findById(any())).thenReturn(Optional.of(kwKafkaConnector));
      kwKafkaConnector.setDocumentation("new docs");
  
      String status = updateData.updateConnectorDocumentation(kwKafkaConnector);
      assertThat(status).isEqualTo(ApiResultStatus.SUCCESS.value);
    }
  
    @ParameterizedTest
    @MethodSource
    public void updateNewUserRequest(
        String userName,
        String mailId,
        String approver,
        boolean isApproved,
        NewUserStatus status,
        boolean userSaved) {
  
      RegisterUserInfo regUser = new RegisterUserInfo();
      regUser.setPwd("XXXXXXXXX");
      regUser.setApprover(approver);
      regUser.setRole("USER");
      regUser.setUsername(userName);
      regUser.setMailid(mailId);
      regUser.setStatus(status.value);
      when(registerInfoRepo.findFirstByUsernameAndStatusIn(eq(userName), any())).thenReturn(regUser);
      updateData.updateNewUserRequest(userName, approver, isApproved);
      if (userSaved) {
        verify(registerInfoRepo, times(1)).save(any());
      }
    }
  
    private static Stream<Arguments> updateNewUserRequest() {
  
      return Stream.of(
          Arguments.of(
              "Octopus", "octopus@klaw-project.io", "SUPERADMIN", true, NewUserStatus.PENDING, true),
          Arguments.of(
              "octopus@klaw-project.io",
              "octopus@klaw-project.io",
              "SUPERADMIN",
              true,
              NewUserStatus.STAGING,
              false),
          Arguments.of(
              "Octopus2",
              "octopus@klaw-project.io",
              "SUPERADMIN",
              true,
              NewUserStatus.DECLINED,
              false),
          Arguments.of(
              "Octopus3",
              "octopus@klaw-project.io",
              "SUPERADMIN",
              true,
              NewUserStatus.APPROVED,
              false));
    }
  }
  