content: package io.aiven.klaw.dao.migration;
  
  import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
  import static org.mockito.ArgumentMatchers.any;
  import static org.mockito.ArgumentMatchers.anyInt;
  import static org.mockito.Mockito.times;
  import static org.mockito.Mockito.verify;
  import static org.mockito.Mockito.when;
  
  import io.aiven.klaw.dao.KafkaConnectorRequest;
  import io.aiven.klaw.dao.Team;
  import io.aiven.klaw.dao.TopicRequest;
  import io.aiven.klaw.dao.UserInfo;
  import io.aiven.klaw.dao.test.MigrationTestData2x1x0;
  import io.aiven.klaw.dao.test.MigrationTestData2x2x0;
  import io.aiven.klaw.error.KlawDataMigrationException;
  import io.aiven.klaw.helpers.db.rdbms.SelectDataJdbc;
  import io.aiven.klaw.helpers.db.rdbms.UpdateDataJdbc;
  import io.aiven.klaw.model.enums.RequestOperationType;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.stream.Collectors;
  import org.junit.jupiter.api.BeforeEach;
  import org.junit.jupiter.api.Test;
  import org.junit.jupiter.api.extension.ExtendWith;
  import org.mockito.Mock;
  import org.springframework.context.annotation.Bean;
  import org.springframework.test.context.junit.jupiter.SpringExtension;
  
  @ExtendWith(SpringExtension.class)
  class MigrateData2x2x0Test {
  
    private MigrateData2x2x0 migrateData2x2x0;
  
    @Mock private SelectDataJdbc selectDataJdbc;
  
    @Mock private UpdateDataJdbc updateDataJdbc;
  
    @Bean
    public MigrationTestData2x1x0 MigrateTestData2x1x0() {
      return new MigrationTestData2x1x0();
    }
  
    @Bean
    public MigrationTestData2x2x0 MigrationTestData2x1x0() {
      return new MigrationTestData2x2x0();
    }
  
    @BeforeEach
    public void setUp() {
      migrateData2x2x0 = new MigrateData2x2x0(selectDataJdbc, updateDataJdbc);
    }
  
    @Test
    public void givenNoTenantsDoNotMigrateAnyData() throws KlawDataMigrationException {
  
      when(selectDataJdbc.selectAllUsersAllTenants()).thenReturn(getUserAndTenantInfo(0));
      when(selectDataJdbc.selectAllTeams(anyInt())).thenReturn(getTeams(0));
  
      boolean success = migrateData2x2x0.migrate();
      verify(selectDataJdbc, times(1)).selectAllUsersAllTenants();
      // No other calls made
      verify(selectDataJdbc, times(0)).selectAllTeams(anyInt());
      verify(selectDataJdbc, times(0)).getAllTopicRequestsByTenantId(anyInt());
      verify(selectDataJdbc, times(0)).getAllConnectorRequestsByTenantId(anyInt());
      assertThat(success).isTrue();
    }
  
    @Test
    public void givenOneTenantButNoClaimsRequestsDoNotMigrateData()
        throws KlawDataMigrationException {
      // Setup
  
      when(selectDataJdbc.selectAllUsersAllTenants()).thenReturn(getUserAndTenantInfo(1));
      when(selectDataJdbc.selectAllTeams(anyInt())).thenReturn(getTeams(2));
      when(selectDataJdbc.getAllTopicRequestsByTenantId(anyInt()))
          .thenReturn(getListOfTopicRequests(0, 0, "0"));
      when(selectDataJdbc.getAllConnectorRequestsByTenantId(anyInt()))
          .thenReturn(getListOfConnectorRequests(0, 0, "0"));
  
      // Execute
      boolean success = migrateData2x2x0.migrate();
  
      // Verify
  
      verify(selectDataJdbc, times(1)).selectAllUsersAllTenants();
      verify(selectDataJdbc, times(1)).getAllTopicRequestsByTenantId(anyInt());
      verify(selectDataJdbc, times(1)).getAllConnectorRequestsByTenantId(anyInt());
      // No Claim Requests so no saving updates back to DB
      verify(updateDataJdbc, times(0)).updateTopicRequest(any());
      verify(updateDataJdbc, times(0)).updateConnectorRequest(any());
      assertThat(success).isTrue();
    }
  
    @Test
    public void givenOneTenantWithReqeuestsButNoClaimsRequestsDoNotMigrateData()
        throws KlawDataMigrationException {
      // Setup
  
      when(selectDataJdbc.selectAllUsersAllTenants()).thenReturn(getUserAndTenantInfo(1));
      when(selectDataJdbc.selectAllTeams(anyInt())).thenReturn(getTeams(2));
      when(selectDataJdbc.getAllTopicRequestsByTenantId(anyInt()))
          .thenReturn(getListOfTopicRequests(8, 0, "0"));
      when(selectDataJdbc.getAllConnectorRequestsByTenantId(anyInt()))
          .thenReturn(getListOfConnectorRequests(8, 0, "0"));
  
      // Execute
      boolean success = migrateData2x2x0.migrate();
  
      // Verify
      verify(selectDataJdbc, times(1)).selectAllUsersAllTenants();
      verify(selectDataJdbc, times(1)).getAllTopicRequestsByTenantId(anyInt());
      verify(selectDataJdbc, times(1)).getAllConnectorRequestsByTenantId(anyInt());
      // No Claim Requests so no saving updates back to DB
      verify(updateDataJdbc, times(0)).updateTopicRequest(any());
      verify(updateDataJdbc, times(0)).updateConnectorRequest(any());
      assertThat(success).isTrue();
    }
  
    @Test
    public void givenOneTenantWithReqeuestsAndOneClaimsRequestsMigrateOneData()
        throws KlawDataMigrationException {
      // Setup
  
      when(selectDataJdbc.selectAllUsersAllTenants()).thenReturn(getUserAndTenantInfo(1));
      when(selectDataJdbc.selectAllTeams(anyInt())).thenReturn(getTeams(2));
      when(selectDataJdbc.getAllTopicRequestsByTenantId(anyInt()))
          .thenReturn(getListOfTopicRequests(8, 0, "0"));
      when(selectDataJdbc.getAllConnectorRequestsByTenantId(anyInt()))
          .thenReturn(getListOfConnectorRequests(8, 1, "1"));
  
      // Execute
      boolean success = migrateData2x2x0.migrate();
  
      // Verify
  
      verify(selectDataJdbc, times(1)).selectAllUsersAllTenants();
      verify(selectDataJdbc, times(1)).getAllTopicRequestsByTenantId(anyInt());
  
      verify(selectDataJdbc, times(1)).getAllConnectorRequestsByTenantId(anyInt());
      // No Claim Requests so no saving updates back to DB
      verify(updateDataJdbc, times(0)).updateTopicRequest(any());
      // One Claim requests ensure it is saved back.
      verify(updateDataJdbc, times(1)).updateConnectorRequest(any());
      assertThat(success).isTrue();
    }
  
    @Test
    public void
        givenOneTenantWithReqeuestsAndOneClaimsRequestsButDataInDescriptionIsNotTeamIdDoNotMigrateOneData()
            throws KlawDataMigrationException {
      // Setup
  
      when(selectDataJdbc.selectAllUsersAllTenants()).thenReturn(getUserAndTenantInfo(1));
      when(selectDataJdbc.selectAllTeams(anyInt())).thenReturn(getTeams(2));
      when(selectDataJdbc.getAllTopicRequestsByTenantId(anyInt()))
          .thenReturn(getListOfTopicRequests(8, 0, "0"));
      when(selectDataJdbc.getAllConnectorRequestsByTenantId(anyInt()))
          .thenReturn(getListOfConnectorRequests(8, 1, "A description"));
  
      // Execute
      boolean success = migrateData2x2x0.migrate();
  
      // Verify
  
      verify(selectDataJdbc, times(1)).selectAllUsersAllTenants();
      verify(selectDataJdbc, times(1)).getAllTopicRequestsByTenantId(anyInt());
  
      verify(selectDataJdbc, times(1)).getAllConnectorRequestsByTenantId(anyInt());
      // No Claim Requests so no saving updates back to DB
      verify(updateDataJdbc, times(0)).updateTopicRequest(any());
      // One Claim requests but description is text not number so it wont update.
      verify(updateDataJdbc, times(0)).updateConnectorRequest(any());
      assertThat(success).isTrue();
    }
  
    @Test
    public void givenOneTenantWithReqeuestsAndAlreadyMigratedClaimsRequestsDoNotMigrateData()
        throws KlawDataMigrationException {
      // Setup
  
      when(selectDataJdbc.selectAllUsersAllTenants()).thenReturn(getUserAndTenantInfo(1));
      when(selectDataJdbc.selectAllTeams(anyInt())).thenReturn(getTeams(2));
      when(selectDataJdbc.getAllTopicRequestsByTenantId(anyInt()))
          .thenReturn(setTopicApprovingTeamId(getListOfTopicRequests(33, 3, "2")));
      when(selectDataJdbc.getAllConnectorRequestsByTenantId(anyInt()))
          .thenReturn(setConnectorApprovingTeamId(getListOfConnectorRequests(18, 8, "1")));
  
      // Execute
      boolean success = migrateData2x2x0.migrate();
  
      // Verify
      verify(selectDataJdbc, times(1)).selectAllUsersAllTenants();
      verify(selectDataJdbc, times(1)).getAllTopicRequestsByTenantId(anyInt());
  
      verify(selectDataJdbc, times(1)).getAllConnectorRequestsByTenantId(anyInt());
      // No Claim Requests so no saving updates back to DB
      verify(updateDataJdbc, times(0)).updateTopicRequest(any());
      // One Claim requests but description is text not number so it wont update.
      verify(updateDataJdbc, times(0)).updateConnectorRequest(any());
  
      assertThat(success).isTrue();
    }
  
    @Test
    public void givenOneTenantWithReqeuestsAndNoMigratedClaimsRequestsMigrateData()
        throws KlawDataMigrationException {
      // Setup
  
      when(selectDataJdbc.selectAllUsersAllTenants()).thenReturn(getUserAndTenantInfo(1));
      when(selectDataJdbc.selectAllTeams(anyInt())).thenReturn(getTeams(2));
      when(selectDataJdbc.getAllTopicRequestsByTenantId(anyInt()))
          .thenReturn(getListOfTopicRequests(33, 3, "2"));
      when(selectDataJdbc.getAllConnectorRequestsByTenantId(anyInt()))
          .thenReturn(getListOfConnectorRequests(18, 8, "1"));
  
      // Execute
      boolean success = migrateData2x2x0.migrate();
  
      // Verify
      verify(selectDataJdbc, times(1)).selectAllUsersAllTenants();
      verify(selectDataJdbc, times(1)).getAllTopicRequestsByTenantId(anyInt());
      verify(selectDataJdbc, times(1)).getAllConnectorRequestsByTenantId(anyInt());
      // No Claim Requests so no saving updates back to DB
      verify(updateDataJdbc, times(3)).updateTopicRequest(any());
      // One Claim requests but description is text not number so it wont update.
      verify(updateDataJdbc, times(8)).updateConnectorRequest(any());
  
      assertThat(success).isTrue();
    }
  
    @Test
    public void givenThreeTenantsWithAMixOfRequestsToMigrateAndNotMigrateMigrateData()
        throws KlawDataMigrationException {
      // Setup
  
      when(selectDataJdbc.selectAllUsersAllTenants()).thenReturn(getUserAndTenantInfo(3));
      when(selectDataJdbc.selectAllTeams(anyInt())).thenReturn(getTeams(2));
      when(selectDataJdbc.getAllTopicRequestsByTenantId(anyInt()))
          .thenReturn(getListOfTopicRequests(33, 3, "2"))
          .thenReturn(setTopicApprovingTeamId(getListOfTopicRequests(33, 30, "2")))
          .thenReturn(getListOfTopicRequests(13, 8, "2"));
      when(selectDataJdbc.getAllConnectorRequestsByTenantId(anyInt()))
          .thenReturn(getListOfConnectorRequests(18, 8, "1"))
          .thenReturn(setConnectorApprovingTeamId(getListOfConnectorRequests(18, 8, "1")))
          .thenReturn(getListOfConnectorRequests(43, 13, "2"));
  
      // Execute
      boolean success = migrateData2x2x0.migrate();
  
      // Verify
      verify(selectDataJdbc, times(1)).selectAllUsersAllTenants();
      verify(selectDataJdbc, times(3)).getAllTopicRequestsByTenantId(anyInt());
      verify(selectDataJdbc, times(3)).getAllConnectorRequestsByTenantId(anyInt());
  
      // Topic Requests & Connector Requests have a mix of allready updated and non updated claims.
      // So we expect 11 topic reqs and 21 connector requests
      verify(updateDataJdbc, times(11)).updateTopicRequest(any());
      verify(updateDataJdbc, times(21)).updateConnectorRequest(any());
  
      assertThat(success).isTrue();
    }
  
    private List<TopicRequest> getListOfTopicRequests(
        int numberOfRequests, int numberOfClaimRequests, String desc) {
      List<TopicRequest> requests = new ArrayList<>();
      for (int i = 0; i < numberOfRequests; i++) {
        TopicRequest request = new TopicRequest();
        request.setTenantId(101 + i);
        request.setTeamId(1 + i);
        request.setDescription(desc);
        request.setRequestor("User" + i);
        if (i < numberOfClaimRequests) {
          request.setRequestOperationType(RequestOperationType.CLAIM.value);
        } else {
          request.setRequestOperationType(RequestOperationType.CREATE.value);
        }
  
        requests.add(request);
      }
  
      return requests;
    }
  
    private List<KafkaConnectorRequest> getListOfConnectorRequests(
        int numberOfRequests, int numberOfClaimRequests, String desc) {
      List<KafkaConnectorRequest> requests = new ArrayList<>();
      for (int i = 0; i < numberOfRequests; i++) {
        KafkaConnectorRequest request = new KafkaConnectorRequest();
        request.setTenantId(101 + i);
        request.setTeamId(1 + i);
        request.setDescription(desc);
        request.setRequestor("User" + i);
        if (i < numberOfClaimRequests) {
          request.setRequestOperationType(RequestOperationType.CLAIM.value);
        } else {
          request.setRequestOperationType(RequestOperationType.CREATE.value);
        }
  
        requests.add(request);
      }
  
      return requests;
    }
  
    private List<TopicRequest> setTopicApprovingTeamId(List<TopicRequest> requests) {
  
      return requests.stream()
          .map(
              req -> {
                if (req.getRequestOperationType().equals(RequestOperationType.CLAIM.value)) {
                  req.setApprovingTeamId(req.getDescription());
                }
                return req;
              })
          .collect(Collectors.toList());
    }
  
    private List<KafkaConnectorRequest> setConnectorApprovingTeamId(
        List<KafkaConnectorRequest> requests) {
  
      return requests.stream()
          .map(
              req -> {
                if (req.getRequestOperationType().equals(RequestOperationType.CLAIM.value)) {
                  req.setApprovingTeamId(req.getDescription());
                }
                return req;
              })
          .collect(Collectors.toList());
    }
  
    private List<UserInfo> getUserAndTenantInfo(int numberOfEntries) {
      List<UserInfo> users = new ArrayList<>();
      for (int i = 0; i < numberOfEntries; i++) {
        UserInfo info = new UserInfo();
        info.setTenantId(101 + i);
        info.setTeamId(1 + i);
        info.setRole("User");
        info.setUsername("User" + i);
        info.setFullname("User" + i + " LastName");
        info.setSwitchTeams(false);
        users.add(info);
      }
  
      return users;
    }
  
    private List<Team> getTeams(int numberOfEntries) {
      List<Team> teams = new ArrayList<>();
      for (int i = 0; i < numberOfEntries; i++) {
        Team info = new Team();
        info.setTenantId(101 + i);
        info.setTeamId(1 + i);
        teams.add(info);
      }
  
      return teams;
    }
  }
  