diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..74f5825021 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,36 @@ +{ + "name": "Java", + + "image": "mcr.microsoft.com/devcontainers/java:0-17", + + "features": { + "ghcr.io/devcontainers/features/java:1": { + "version": "none", + "installMaven": "true", + "installGradle": "false" + }, + "ghcr.io/devcontainers/features/docker-in-docker:2": {} + }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "java -version", + + "customizations": { + "vscode": { + "extensions" : [ + "vscjava.vscode-java-pack", + "vscjava.vscode-maven", + "vscjava.vscode-java-debug", + "EditorConfig.EditorConfig", + "ms-azuretools.vscode-docker", + "antfu.vite", + "ms-kubernetes-tools.vscode-kubernetes-tools", + "github.vscode-pull-request-github" + ] + } + } + +} diff --git a/.github/workflows/e2e-automation.yml b/.github/workflows/e2e-automation.yml index eb10985747..5ce1437614 100644 --- a/.github/workflows/e2e-automation.yml +++ b/.github/workflows/e2e-automation.yml @@ -36,7 +36,7 @@ jobs: - name: Pull with Docker id: pull_chrome run: | - docker pull selenium/standalone-chrome:103.0 + docker pull selenoid/vnc_chrome:103.0 - name: Set up JDK uses: actions/setup-java@v3 with: @@ -52,6 +52,7 @@ jobs: id: compose_app # use the following command until #819 will be fixed run: | + docker-compose -f kafka-ui-e2e-checks/docker/selenoid-git.yaml up -d docker-compose -f ./documentation/compose/e2e-tests.yaml up -d - name: Run test suite run: | @@ -78,7 +79,7 @@ jobs: uses: Sibz/github-status-action@v1.1.6 with: authToken: ${{secrets.GITHUB_TOKEN}} - context: "Test report" + context: "Click Details button to open Allure report" state: "success" sha: ${{ github.sha }} target_url: http://kafkaui-allure-reports.s3-website.eu-central-1.amazonaws.com/${{ github.run_number }} diff --git a/.github/workflows/e2e-checks.yaml b/.github/workflows/e2e-checks.yaml index 83be371bea..771eb698fe 100644 --- a/.github/workflows/e2e-checks.yaml +++ b/.github/workflows/e2e-checks.yaml @@ -15,20 +15,20 @@ jobs: - uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} - - name: Configure AWS credentials for Kafka-UI account + - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v2 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: eu-central-1 - - name: Set the values + - name: Set up environment id: set_env_values run: | cat "./kafka-ui-e2e-checks/.env.ci" >> "./kafka-ui-e2e-checks/.env" - - name: pull docker + - name: Pull with Docker id: pull_chrome run: | - docker pull selenium/standalone-chrome:103.0 + docker pull selenoid/vnc_chrome:103.0 - name: Set up JDK uses: actions/setup-java@v3 with: @@ -40,12 +40,13 @@ jobs: run: | ./mvnw -B -ntp versions:set -DnewVersion=${{ github.event.pull_request.head.sha }} ./mvnw -B -V -ntp clean install -Pprod -Dmaven.test.skip=true ${{ github.event.inputs.extraMavenOptions }} - - name: compose app + - name: Compose with Docker id: compose_app # use the following command until #819 will be fixed run: | + docker-compose -f kafka-ui-e2e-checks/docker/selenoid-git.yaml up -d docker-compose -f ./documentation/compose/e2e-tests.yaml up -d - - name: e2e run + - name: Run test suite run: | ./mvnw -B -ntp versions:set -DnewVersion=${{ github.event.pull_request.head.sha }} ./mvnw -B -V -ntp -Dsurefire.suiteXmlFiles='src/test/resources/smoke.xml' -f 'kafka-ui-e2e-checks' test -Pprod @@ -65,7 +66,7 @@ jobs: AWS_S3_BUCKET: 'kafkaui-allure-reports' AWS_REGION: 'eu-central-1' SOURCE_DIR: 'allure-history/allure-results' - - name: Post the link to allure report + - name: Deploy report to Amazon S3 if: always() uses: Sibz/github-status-action@v1.1.6 with: diff --git a/.github/workflows/e2e-weekly.yml b/.github/workflows/e2e-weekly.yml index 4683c7e111..ea5ca7e522 100644 --- a/.github/workflows/e2e-weekly.yml +++ b/.github/workflows/e2e-weekly.yml @@ -23,7 +23,7 @@ jobs: - name: Pull with Docker id: pull_chrome run: | - docker pull selenium/standalone-chrome:103.0 + docker pull selenoid/vnc_chrome:103.0 - name: Set up JDK uses: actions/setup-java@v3 with: @@ -39,6 +39,7 @@ jobs: id: compose_app # use the following command until #819 will be fixed run: | + docker-compose -f kafka-ui-e2e-checks/docker/selenoid-git.yaml up -d docker-compose -f ./documentation/compose/e2e-tests.yaml up -d - name: Run test suite run: | @@ -65,7 +66,7 @@ jobs: uses: Sibz/github-status-action@v1.1.6 with: authToken: ${{secrets.GITHUB_TOKEN}} - context: "Test report" + context: "Click Details button to open Allure report" state: "success" sha: ${{ github.sha }} target_url: http://kafkaui-allure-reports.s3-website.eu-central-1.amazonaws.com/${{ github.run_number }} diff --git a/documentation/compose/e2e-tests.yaml b/documentation/compose/e2e-tests.yaml index 2a422c54d4..ae56f5d576 100644 --- a/documentation/compose/e2e-tests.yaml +++ b/documentation/compose/e2e-tests.yaml @@ -11,14 +11,14 @@ services: test: wget --no-verbose --tries=1 --spider http://localhost:8080/actuator/health interval: 30s timeout: 10s - retries: 10 + retries: 10 depends_on: - kafka0: - condition: service_healthy - schemaregistry0: - condition: service_healthy - kafka-connect0: - condition: service_healthy + kafka0: + condition: service_healthy + schemaregistry0: + condition: service_healthy + kafka-connect0: + condition: service_healthy environment: KAFKA_CLUSTERS_0_NAME: local KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka0:29092 @@ -33,10 +33,10 @@ services: hostname: kafka0 container_name: kafka0 healthcheck: - test: unset JMX_PORT && KAFKA_JMX_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=kafka0 -Dcom.sun.management.jmxremote.rmi.port=9999" && kafka-broker-api-versions --bootstrap-server=localhost:9092 - interval: 30s - timeout: 10s - retries: 10 + test: unset JMX_PORT && KAFKA_JMX_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=kafka0 -Dcom.sun.management.jmxremote.rmi.port=9999" && kafka-broker-api-versions --bootstrap-server=localhost:9092 + interval: 30s + timeout: 10s + retries: 10 ports: - "9092:9092" - "9997:9997" @@ -68,12 +68,12 @@ services: - 8085:8085 depends_on: kafka0: - condition: service_healthy + condition: service_healthy healthcheck: - test: ["CMD", "timeout", "1", "curl", "--silent", "--fail", "http://schemaregistry0:8085/subjects"] - interval: 30s - timeout: 10s - retries: 10 + test: [ "CMD", "timeout", "1", "curl", "--silent", "--fail", "http://schemaregistry0:8085/subjects" ] + interval: 30s + timeout: 10s + retries: 10 environment: SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS: PLAINTEXT://kafka0:29092 SCHEMA_REGISTRY_KAFKASTORE_SECURITY_PROTOCOL: PLAINTEXT @@ -93,11 +93,11 @@ services: - 8083:8083 depends_on: kafka0: - condition: service_healthy + condition: service_healthy schemaregistry0: - condition: service_healthy + condition: service_healthy healthcheck: - test: ["CMD", "nc", "127.0.0.1", "8083"] + test: [ "CMD", "nc", "127.0.0.1", "8083" ] interval: 30s timeout: 10s retries: 10 @@ -118,8 +118,8 @@ services: CONNECT_INTERNAL_VALUE_CONVERTER: org.apache.kafka.connect.json.JsonConverter CONNECT_REST_ADVERTISED_HOST_NAME: kafka-connect0 CONNECT_PLUGIN_PATH: "/usr/share/java,/usr/share/confluent-hub-components" -# AWS_ACCESS_KEY_ID: "" -# AWS_SECRET_ACCESS_KEY: "" + # AWS_ACCESS_KEY_ID: "" + # AWS_SECRET_ACCESS_KEY: "" kafka-init-topics: image: confluentinc/cp-kafka:7.2.1 @@ -127,7 +127,7 @@ services: - ./message.json:/data/message.json depends_on: kafka0: - condition: service_healthy + condition: service_healthy command: "bash -c 'echo Waiting for Kafka to be ready... && \ cub kafka-ready -b kafka0:29092 1 30 && \ kafka-topics --create --topic users --partitions 3 --replication-factor 1 --if-not-exists --bootstrap-server kafka0:29092 && \ @@ -142,10 +142,10 @@ services: ports: - 5432:5432 healthcheck: - test: ["CMD-SHELL", "pg_isready -U dev_user"] + test: [ "CMD-SHELL", "pg_isready -U dev_user" ] interval: 10s timeout: 5s - retries: 5 + retries: 5 environment: POSTGRES_USER: 'dev_user' POSTGRES_PASSWORD: '12345' @@ -154,7 +154,7 @@ services: image: ellerbrock/alpine-bash-curl-ssl depends_on: postgres-db: - condition: service_healthy + condition: service_healthy kafka-connect0: condition: service_healthy volumes: @@ -164,7 +164,7 @@ services: ksqldb: image: confluentinc/ksqldb-server:0.18.0 healthcheck: - test: ["CMD", "timeout", "1", "curl", "--silent", "--fail", "http://localhost:8088/info"] + test: [ "CMD", "timeout", "1", "curl", "--silent", "--fail", "http://localhost:8088/info" ] interval: 30s timeout: 10s retries: 10 @@ -174,7 +174,7 @@ services: kafka-connect0: condition: service_healthy schemaregistry0: - condition: service_healthy + condition: service_healthy ports: - 8088:8088 environment: diff --git a/etc/checkstyle/checkstyle-e2e.xml b/etc/checkstyle/checkstyle-e2e.xml new file mode 100644 index 0000000000..c2af9c987b --- /dev/null +++ b/etc/checkstyle/checkstyle-e2e.xml @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/etc/checkstyle/checkstyle.xml b/etc/checkstyle/checkstyle.xml index 0348f809b4..745f1bc368 100644 --- a/etc/checkstyle/checkstyle.xml +++ b/etc/checkstyle/checkstyle.xml @@ -318,7 +318,7 @@ - + @@ -330,4 +330,4 @@ - \ No newline at end of file + diff --git a/kafka-ui-api/Dockerfile b/kafka-ui-api/Dockerfile index fcd29c0f06..d969ec7631 100644 --- a/kafka-ui-api/Dockerfile +++ b/kafka-ui-api/Dockerfile @@ -1,4 +1,5 @@ -FROM azul/zulu-openjdk-alpine:17-jre +#FROM azul/zulu-openjdk-alpine:17-jre-headless +FROM azul/zulu-openjdk-alpine@sha256:a36679ac0d28cb835e2a8c00e1e0d95509c6c51c5081c7782b85edb1f37a771a RUN apk add --no-cache gcompat # need to make snappy codec work RUN addgroup -S kafkaui && adduser -S kafkaui -G kafkaui diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/client/RetryingKafkaConnectClient.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/client/RetryingKafkaConnectClient.java index 5ec5a779d3..74b9485008 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/client/RetryingKafkaConnectClient.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/client/RetryingKafkaConnectClient.java @@ -6,7 +6,13 @@ import com.provectus.kafka.ui.config.ClustersProperties; import com.provectus.kafka.ui.connect.ApiClient; import com.provectus.kafka.ui.connect.api.KafkaConnectClientApi; import com.provectus.kafka.ui.connect.model.Connector; +import com.provectus.kafka.ui.connect.model.ConnectorPlugin; +import com.provectus.kafka.ui.connect.model.ConnectorPluginConfigValidationResponse; +import com.provectus.kafka.ui.connect.model.ConnectorStatus; +import com.provectus.kafka.ui.connect.model.ConnectorTask; +import com.provectus.kafka.ui.connect.model.ConnectorTopics; import com.provectus.kafka.ui.connect.model.NewConnector; +import com.provectus.kafka.ui.connect.model.TaskStatus; import com.provectus.kafka.ui.exception.KafkaConnectConflictReponseException; import com.provectus.kafka.ui.exception.ValidationException; import com.provectus.kafka.ui.util.WebClientConfigurator; @@ -15,11 +21,7 @@ import java.util.List; import java.util.Map; import javax.annotation.Nullable; import lombok.extern.slf4j.Slf4j; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.util.MultiValueMap; +import org.springframework.http.ResponseEntity; import org.springframework.util.unit.DataSize; import org.springframework.web.client.RestClientException; import org.springframework.web.reactive.function.client.WebClient; @@ -79,6 +81,176 @@ public class RetryingKafkaConnectClient extends KafkaConnectClientApi { ); } + @Override + public Mono> createConnectorWithHttpInfo(NewConnector newConnector) + throws WebClientResponseException { + return withRetryOnConflict(super.createConnectorWithHttpInfo(newConnector)); + } + + @Override + public Mono deleteConnector(String connectorName) throws WebClientResponseException { + return withRetryOnConflict(super.deleteConnector(connectorName)); + } + + @Override + public Mono> deleteConnectorWithHttpInfo(String connectorName) + throws WebClientResponseException { + return withRetryOnConflict(super.deleteConnectorWithHttpInfo(connectorName)); + } + + + @Override + public Mono getConnector(String connectorName) throws WebClientResponseException { + return withRetryOnConflict(super.getConnector(connectorName)); + } + + @Override + public Mono> getConnectorWithHttpInfo(String connectorName) + throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorWithHttpInfo(connectorName)); + } + + @Override + public Mono> getConnectorConfig(String connectorName) throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorConfig(connectorName)); + } + + @Override + public Mono>> getConnectorConfigWithHttpInfo(String connectorName) + throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorConfigWithHttpInfo(connectorName)); + } + + @Override + public Flux getConnectorPlugins() throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorPlugins()); + } + + @Override + public Mono>> getConnectorPluginsWithHttpInfo() + throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorPluginsWithHttpInfo()); + } + + @Override + public Mono getConnectorStatus(String connectorName) throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorStatus(connectorName)); + } + + @Override + public Mono> getConnectorStatusWithHttpInfo(String connectorName) + throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorStatusWithHttpInfo(connectorName)); + } + + @Override + public Mono getConnectorTaskStatus(String connectorName, Integer taskId) + throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorTaskStatus(connectorName, taskId)); + } + + @Override + public Mono> getConnectorTaskStatusWithHttpInfo(String connectorName, Integer taskId) + throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorTaskStatusWithHttpInfo(connectorName, taskId)); + } + + @Override + public Flux getConnectorTasks(String connectorName) throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorTasks(connectorName)); + } + + @Override + public Mono>> getConnectorTasksWithHttpInfo(String connectorName) + throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorTasksWithHttpInfo(connectorName)); + } + + @Override + public Mono> getConnectorTopics(String connectorName) throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorTopics(connectorName)); + } + + @Override + public Mono>> getConnectorTopicsWithHttpInfo(String connectorName) + throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorTopicsWithHttpInfo(connectorName)); + } + + @Override + public Flux getConnectors(String search) throws WebClientResponseException { + return withRetryOnConflict(super.getConnectors(search)); + } + + @Override + public Mono>> getConnectorsWithHttpInfo(String search) throws WebClientResponseException { + return withRetryOnConflict(super.getConnectorsWithHttpInfo(search)); + } + + @Override + public Mono pauseConnector(String connectorName) throws WebClientResponseException { + return withRetryOnConflict(super.pauseConnector(connectorName)); + } + + @Override + public Mono> pauseConnectorWithHttpInfo(String connectorName) throws WebClientResponseException { + return withRetryOnConflict(super.pauseConnectorWithHttpInfo(connectorName)); + } + + @Override + public Mono restartConnector(String connectorName, Boolean includeTasks, Boolean onlyFailed) + throws WebClientResponseException { + return withRetryOnConflict(super.restartConnector(connectorName, includeTasks, onlyFailed)); + } + + @Override + public Mono> restartConnectorWithHttpInfo(String connectorName, Boolean includeTasks, + Boolean onlyFailed) throws WebClientResponseException { + return withRetryOnConflict(super.restartConnectorWithHttpInfo(connectorName, includeTasks, onlyFailed)); + } + + @Override + public Mono restartConnectorTask(String connectorName, Integer taskId) throws WebClientResponseException { + return withRetryOnConflict(super.restartConnectorTask(connectorName, taskId)); + } + + @Override + public Mono> restartConnectorTaskWithHttpInfo(String connectorName, Integer taskId) + throws WebClientResponseException { + return withRetryOnConflict(super.restartConnectorTaskWithHttpInfo(connectorName, taskId)); + } + + @Override + public Mono resumeConnector(String connectorName) throws WebClientResponseException { + return super.resumeConnector(connectorName); + } + + @Override + public Mono> resumeConnectorWithHttpInfo(String connectorName) + throws WebClientResponseException { + return withRetryOnConflict(super.resumeConnectorWithHttpInfo(connectorName)); + } + + @Override + public Mono> setConnectorConfigWithHttpInfo(String connectorName, + Map requestBody) + throws WebClientResponseException { + return withRetryOnConflict(super.setConnectorConfigWithHttpInfo(connectorName, requestBody)); + } + + @Override + public Mono validateConnectorPluginConfig(String pluginName, + Map requestBody) + throws WebClientResponseException { + return withRetryOnConflict(super.validateConnectorPluginConfig(pluginName, requestBody)); + } + + @Override + public Mono> validateConnectorPluginConfigWithHttpInfo( + String pluginName, Map requestBody) throws WebClientResponseException { + return withRetryOnConflict(super.validateConnectorPluginConfigWithHttpInfo(pluginName, requestBody)); + } + private static class RetryingApiClient extends ApiClient { public RetryingApiClient(ConnectCluster config, @@ -108,35 +280,5 @@ public class RetryingKafkaConnectClient extends KafkaConnectClientApi { .configureBufferSize(maxBuffSize) .build(); } - - @Override - public Mono invokeAPI(String path, HttpMethod method, Map pathParams, - MultiValueMap queryParams, Object body, - HttpHeaders headerParams, - MultiValueMap cookieParams, - MultiValueMap formParams, List accept, - MediaType contentType, String[] authNames, - ParameterizedTypeReference returnType) - throws RestClientException { - return withRetryOnConflict( - super.invokeAPI(path, method, pathParams, queryParams, body, headerParams, cookieParams, - formParams, accept, contentType, authNames, returnType) - ); - } - - @Override - public Flux invokeFluxAPI(String path, HttpMethod method, Map pathParams, - MultiValueMap queryParams, Object body, - HttpHeaders headerParams, - MultiValueMap cookieParams, - MultiValueMap formParams, - List accept, MediaType contentType, - String[] authNames, ParameterizedTypeReference returnType) - throws RestClientException { - return withRetryOnConflict( - super.invokeFluxAPI(path, method, pathParams, queryParams, body, headerParams, - cookieParams, formParams, accept, contentType, authNames, returnType) - ); - } } } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/ClustersProperties.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/ClustersProperties.java index 919e0633e4..15436c1cd8 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/ClustersProperties.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/ClustersProperties.java @@ -1,6 +1,7 @@ package com.provectus.kafka.ui.config; import com.provectus.kafka.ui.model.MetricsConfig; +import jakarta.annotation.PostConstruct; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -8,7 +9,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; -import javax.annotation.PostConstruct; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/auth/OAuthProperties.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/auth/OAuthProperties.java index f79d217fa7..a76403bf70 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/auth/OAuthProperties.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/auth/OAuthProperties.java @@ -1,9 +1,9 @@ package com.provectus.kafka.ui.config.auth; +import jakarta.annotation.PostConstruct; import java.util.HashMap; import java.util.Map; import java.util.Set; -import javax.annotation.PostConstruct; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.Assert; diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/ApplicationConfigController.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/ApplicationConfigController.java index b21ef10c61..571250ba94 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/ApplicationConfigController.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/ApplicationConfigController.java @@ -13,12 +13,12 @@ import com.provectus.kafka.ui.model.ClusterConfigValidationDTO; import com.provectus.kafka.ui.model.RestartRequestDTO; import com.provectus.kafka.ui.model.UploadedFileInfoDTO; import com.provectus.kafka.ui.model.rbac.AccessContext; +import com.provectus.kafka.ui.service.ApplicationInfoService; import com.provectus.kafka.ui.service.KafkaClusterFactory; import com.provectus.kafka.ui.service.rbac.AccessControlService; import com.provectus.kafka.ui.util.ApplicationRestarter; import com.provectus.kafka.ui.util.DynamicConfigOperations; import com.provectus.kafka.ui.util.DynamicConfigOperations.PropertiesStructure; -import java.util.List; import java.util.Map; import javax.annotation.Nullable; import lombok.RequiredArgsConstructor; @@ -53,18 +53,11 @@ public class ApplicationConfigController implements ApplicationConfigApi { private final DynamicConfigOperations dynamicConfigOperations; private final ApplicationRestarter restarter; private final KafkaClusterFactory kafkaClusterFactory; - + private final ApplicationInfoService applicationInfoService; @Override public Mono> getApplicationInfo(ServerWebExchange exchange) { - return Mono.just( - new ApplicationInfoDTO() - .enabledFeatures( - dynamicConfigOperations.dynamicConfigEnabled() - ? List.of(ApplicationInfoDTO.EnabledFeaturesEnum.DYNAMIC_CONFIG) - : List.of() - ) - ).map(ResponseEntity::ok); + return Mono.just(applicationInfoService.getApplicationInfo()).map(ResponseEntity::ok); } @Override diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/KafkaConnectController.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/KafkaConnectController.java index 9ffd901c07..080c6020f9 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/KafkaConnectController.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/KafkaConnectController.java @@ -149,10 +149,9 @@ public class KafkaConnectController extends AbstractController implements KafkaC } @Override - public Mono> setConnectorConfig(String clusterName, - String connectName, + public Mono> setConnectorConfig(String clusterName, String connectName, String connectorName, - @Valid Mono requestBody, + Mono> requestBody, ServerWebExchange exchange) { Mono validateAccess = accessControlService.validateAccess(AccessContext.builder() @@ -164,8 +163,7 @@ public class KafkaConnectController extends AbstractController implements KafkaC return validateAccess.then( kafkaConnectService .setConnectorConfig(getCluster(clusterName), connectName, connectorName, requestBody) - .map(ResponseEntity::ok) - ); + .map(ResponseEntity::ok)); } @Override @@ -242,7 +240,7 @@ public class KafkaConnectController extends AbstractController implements KafkaC @Override public Mono> validateConnectorPluginConfig( - String clusterName, String connectName, String pluginName, @Valid Mono requestBody, + String clusterName, String connectName, String pluginName, @Valid Mono> requestBody, ServerWebExchange exchange) { return kafkaConnectService .validateConnectorPluginConfig( diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/AbstractEmitter.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/AbstractEmitter.java index 646cf81ca6..9ea0526bac 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/AbstractEmitter.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/AbstractEmitter.java @@ -1,9 +1,6 @@ package com.provectus.kafka.ui.emitter; -import com.provectus.kafka.ui.model.TopicMessageDTO; import com.provectus.kafka.ui.model.TopicMessageEventDTO; -import com.provectus.kafka.ui.model.TopicMessagePhaseDTO; -import com.provectus.kafka.ui.serdes.ConsumerRecordDeserializer; import java.time.Duration; import java.time.Instant; import org.apache.kafka.clients.consumer.Consumer; @@ -14,13 +11,12 @@ import reactor.core.publisher.FluxSink; public abstract class AbstractEmitter { - private final ConsumerRecordDeserializer recordDeserializer; - private final ConsumingStats consumingStats = new ConsumingStats(); + private final MessagesProcessing messagesProcessing; private final PollingThrottler throttler; protected final PollingSettings pollingSettings; - protected AbstractEmitter(ConsumerRecordDeserializer recordDeserializer, PollingSettings pollingSettings) { - this.recordDeserializer = recordDeserializer; + protected AbstractEmitter(MessagesProcessing messagesProcessing, PollingSettings pollingSettings) { + this.messagesProcessing = messagesProcessing; this.pollingSettings = pollingSettings; this.throttler = pollingSettings.getPollingThrottler(); } @@ -40,39 +36,27 @@ public abstract class AbstractEmitter { return records; } + protected boolean sendLimitReached() { + return messagesProcessing.limitReached(); + } + protected void sendMessage(FluxSink sink, - ConsumerRecord msg) { - final TopicMessageDTO topicMessage = recordDeserializer.deserialize(msg); - sink.next( - new TopicMessageEventDTO() - .type(TopicMessageEventDTO.TypeEnum.MESSAGE) - .message(topicMessage) - ); + ConsumerRecord msg) { + messagesProcessing.sendMsg(sink, msg); } protected void sendPhase(FluxSink sink, String name) { - sink.next( - new TopicMessageEventDTO() - .type(TopicMessageEventDTO.TypeEnum.PHASE) - .phase(new TopicMessagePhaseDTO().name(name)) - ); + messagesProcessing.sendPhase(sink, name); } protected int sendConsuming(FluxSink sink, - ConsumerRecords records, - long elapsed) { - return consumingStats.sendConsumingEvt(sink, records, elapsed, getFilterApplyErrors(sink)); + ConsumerRecords records, + long elapsed) { + return messagesProcessing.sentConsumingInfo(sink, records, elapsed); } protected void sendFinishStatsAndCompleteSink(FluxSink sink) { - consumingStats.sendFinishEvent(sink, getFilterApplyErrors(sink)); + messagesProcessing.sendFinishEvent(sink); sink.complete(); } - - protected Number getFilterApplyErrors(FluxSink sink) { - return sink.contextView() - .getOrEmpty(MessageFilterStats.class) - .map(MessageFilterStats::getFilterApplyErrors) - .orElse(0); - } } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/BackwardRecordEmitter.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/BackwardRecordEmitter.java index 42f94a1e01..ccd24e8568 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/BackwardRecordEmitter.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/BackwardRecordEmitter.java @@ -2,7 +2,6 @@ package com.provectus.kafka.ui.emitter; import com.provectus.kafka.ui.model.ConsumerPosition; import com.provectus.kafka.ui.model.TopicMessageEventDTO; -import com.provectus.kafka.ui.serdes.ConsumerRecordDeserializer; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -31,9 +30,9 @@ public class BackwardRecordEmitter Supplier> consumerSupplier, ConsumerPosition consumerPosition, int messagesPerPage, - ConsumerRecordDeserializer recordDeserializer, + MessagesProcessing messagesProcessing, PollingSettings pollingSettings) { - super(recordDeserializer, pollingSettings); + super(messagesProcessing, pollingSettings); this.consumerPosition = consumerPosition; this.messagesPerPage = messagesPerPage; this.consumerSupplier = consumerSupplier; @@ -52,7 +51,7 @@ public class BackwardRecordEmitter int msgsToPollPerPartition = (int) Math.ceil((double) messagesPerPage / readUntilOffsets.size()); log.debug("'Until' offsets for polling: {}", readUntilOffsets); - while (!sink.isCancelled() && !readUntilOffsets.isEmpty()) { + while (!sink.isCancelled() && !readUntilOffsets.isEmpty() && !sendLimitReached()) { new TreeMap<>(readUntilOffsets).forEach((tp, readToOffset) -> { if (sink.isCancelled()) { return; //fast return in case of sink cancellation @@ -61,8 +60,6 @@ public class BackwardRecordEmitter long readFromOffset = Math.max(beginOffset, readToOffset - msgsToPollPerPartition); partitionPollIteration(tp, readFromOffset, readToOffset, consumer, sink) - .stream() - .filter(r -> !sink.isCancelled()) .forEach(r -> sendMessage(sink, r)); if (beginOffset == readFromOffset) { @@ -106,6 +103,7 @@ public class BackwardRecordEmitter EmptyPollsCounter emptyPolls = pollingSettings.createEmptyPollsCounter(); while (!sink.isCancelled() + && !sendLimitReached() && recordsToSend.size() < desiredMsgsToPoll && !emptyPolls.noDataEmptyPollsReached()) { var polledRecords = poll(sink, consumer, pollingSettings.getPartitionPollTimeout()); diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/ConsumingStats.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/ConsumingStats.java index 68c1cff098..0e002f36a4 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/ConsumingStats.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/ConsumingStats.java @@ -19,7 +19,7 @@ class ConsumingStats { int sendConsumingEvt(FluxSink sink, ConsumerRecords polledRecords, long elapsed, - Number filterApplyErrors) { + int filterApplyErrors) { int polledBytes = ConsumerRecordsUtil.calculatePolledSize(polledRecords); bytes += polledBytes; this.records += polledRecords.count(); @@ -32,7 +32,7 @@ class ConsumingStats { return polledBytes; } - void sendFinishEvent(FluxSink sink, Number filterApplyErrors) { + void sendFinishEvent(FluxSink sink, int filterApplyErrors) { sink.next( new TopicMessageEventDTO() .type(TopicMessageEventDTO.TypeEnum.DONE) @@ -41,12 +41,12 @@ class ConsumingStats { } private TopicMessageConsumingDTO createConsumingStats(FluxSink sink, - Number filterApplyErrors) { + int filterApplyErrors) { return new TopicMessageConsumingDTO() .bytesConsumed(this.bytes) .elapsedMs(this.elapsed) .isCancelled(sink.isCancelled()) - .filterApplyErrors(filterApplyErrors.intValue()) + .filterApplyErrors(filterApplyErrors) .messagesConsumed(this.records); } } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/ForwardRecordEmitter.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/ForwardRecordEmitter.java index 971e2f7c9c..8f85e0a8ba 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/ForwardRecordEmitter.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/ForwardRecordEmitter.java @@ -2,7 +2,6 @@ package com.provectus.kafka.ui.emitter; import com.provectus.kafka.ui.model.ConsumerPosition; import com.provectus.kafka.ui.model.TopicMessageEventDTO; -import com.provectus.kafka.ui.serdes.ConsumerRecordDeserializer; import java.util.function.Supplier; import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.consumer.ConsumerRecord; @@ -23,9 +22,9 @@ public class ForwardRecordEmitter public ForwardRecordEmitter( Supplier> consumerSupplier, ConsumerPosition position, - ConsumerRecordDeserializer recordDeserializer, + MessagesProcessing messagesProcessing, PollingSettings pollingSettings) { - super(recordDeserializer, pollingSettings); + super(messagesProcessing, pollingSettings); this.position = position; this.consumerSupplier = consumerSupplier; } @@ -40,6 +39,7 @@ public class ForwardRecordEmitter EmptyPollsCounter emptyPolls = pollingSettings.createEmptyPollsCounter(); while (!sink.isCancelled() + && !sendLimitReached() && !seekOperations.assignedPartitionsFullyPolled() && !emptyPolls.noDataEmptyPollsReached()) { @@ -50,11 +50,7 @@ public class ForwardRecordEmitter log.debug("{} records polled", records.count()); for (ConsumerRecord msg : records) { - if (!sink.isCancelled()) { - sendMessage(sink, msg); - } else { - break; - } + sendMessage(sink, msg); } } sendFinishStatsAndCompleteSink(sink); diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/MessageFilterStats.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/MessageFilterStats.java deleted file mode 100644 index 3b6df3cdea..0000000000 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/MessageFilterStats.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.provectus.kafka.ui.emitter; - -import java.util.concurrent.atomic.AtomicLong; -import lombok.AccessLevel; -import lombok.Getter; - -public class MessageFilterStats { - - @Getter(AccessLevel.PACKAGE) - private final AtomicLong filterApplyErrors = new AtomicLong(); - - public final void incrementApplyErrors() { - filterApplyErrors.incrementAndGet(); - } - -} diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/MessagesProcessing.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/MessagesProcessing.java new file mode 100644 index 0000000000..b6d23bc90d --- /dev/null +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/MessagesProcessing.java @@ -0,0 +1,82 @@ +package com.provectus.kafka.ui.emitter; + +import com.provectus.kafka.ui.model.TopicMessageDTO; +import com.provectus.kafka.ui.model.TopicMessageEventDTO; +import com.provectus.kafka.ui.model.TopicMessagePhaseDTO; +import com.provectus.kafka.ui.serdes.ConsumerRecordDeserializer; +import java.util.function.Predicate; +import javax.annotation.Nullable; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.common.utils.Bytes; +import reactor.core.publisher.FluxSink; + +@Slf4j +public class MessagesProcessing { + + private final ConsumingStats consumingStats = new ConsumingStats(); + private long sentMessages = 0; + private int filterApplyErrors = 0; + + private final ConsumerRecordDeserializer deserializer; + private final Predicate filter; + private final @Nullable Integer limit; + + public MessagesProcessing(ConsumerRecordDeserializer deserializer, + Predicate filter, + @Nullable Integer limit) { + this.deserializer = deserializer; + this.filter = filter; + this.limit = limit; + } + + boolean limitReached() { + return limit != null && sentMessages >= limit; + } + + void sendMsg(FluxSink sink, ConsumerRecord rec) { + if (!sink.isCancelled() && !limitReached()) { + TopicMessageDTO topicMessage = deserializer.deserialize(rec); + try { + if (filter.test(topicMessage)) { + sink.next( + new TopicMessageEventDTO() + .type(TopicMessageEventDTO.TypeEnum.MESSAGE) + .message(topicMessage) + ); + sentMessages++; + } + } catch (Exception e) { + filterApplyErrors++; + log.trace("Error applying filter for message {}", topicMessage); + } + } + } + + int sentConsumingInfo(FluxSink sink, + ConsumerRecords polledRecords, + long elapsed) { + if (!sink.isCancelled()) { + return consumingStats.sendConsumingEvt(sink, polledRecords, elapsed, filterApplyErrors); + } + return 0; + } + + void sendFinishEvent(FluxSink sink) { + if (!sink.isCancelled()) { + consumingStats.sendFinishEvent(sink, filterApplyErrors); + } + } + + void sendPhase(FluxSink sink, String name) { + if (!sink.isCancelled()) { + sink.next( + new TopicMessageEventDTO() + .type(TopicMessageEventDTO.TypeEnum.PHASE) + .phase(new TopicMessagePhaseDTO().name(name)) + ); + } + } + +} diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/TailingEmitter.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/TailingEmitter.java index 4554069c1c..b17d69a09b 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/TailingEmitter.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/TailingEmitter.java @@ -2,7 +2,6 @@ package com.provectus.kafka.ui.emitter; import com.provectus.kafka.ui.model.ConsumerPosition; import com.provectus.kafka.ui.model.TopicMessageEventDTO; -import com.provectus.kafka.ui.serdes.ConsumerRecordDeserializer; import java.util.HashMap; import java.util.function.Supplier; import lombok.extern.slf4j.Slf4j; @@ -20,9 +19,9 @@ public class TailingEmitter extends AbstractEmitter public TailingEmitter(Supplier> consumerSupplier, ConsumerPosition consumerPosition, - ConsumerRecordDeserializer recordDeserializer, + MessagesProcessing messagesProcessing, PollingSettings pollingSettings) { - super(recordDeserializer, pollingSettings); + super(messagesProcessing, pollingSettings); this.consumerSupplier = consumerSupplier; this.consumerPosition = consumerPosition; } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/exception/GlobalErrorWebExceptionHandler.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/exception/GlobalErrorWebExceptionHandler.java index 394e2aa730..8ad83fe47d 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/exception/GlobalErrorWebExceptionHandler.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/exception/GlobalErrorWebExceptionHandler.java @@ -134,7 +134,7 @@ public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHan .timestamp(currentTimestamp()) .stackTrace(Throwables.getStackTraceAsString(exception)); return ServerResponse - .status(exception.getStatus()) + .status(exception.getStatusCode()) .contentType(MediaType.APPLICATION_JSON) .bodyValue(response); } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/rbac/Permission.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/rbac/Permission.java index 9b0b4c163e..16f01f60e6 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/rbac/Permission.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/rbac/Permission.java @@ -1,5 +1,6 @@ package com.provectus.kafka.ui.model.rbac; +import static com.provectus.kafka.ui.model.rbac.Resource.APPLICATIONCONFIG; import static com.provectus.kafka.ui.model.rbac.Resource.CLUSTERCONFIG; import static com.provectus.kafka.ui.model.rbac.Resource.KSQL; @@ -26,6 +27,8 @@ import org.springframework.util.Assert; @EqualsAndHashCode public class Permission { + private static final List RBAC_ACTION_EXEMPT_LIST = List.of(KSQL, CLUSTERCONFIG, APPLICATIONCONFIG); + Resource resource; List actions; @@ -51,7 +54,7 @@ public class Permission { public void validate() { Assert.notNull(resource, "resource cannot be null"); - if (!List.of(KSQL, CLUSTERCONFIG).contains(this.resource)) { + if (!RBAC_ACTION_EXEMPT_LIST.contains(this.resource)) { Assert.notNull(value, "permission value can't be empty for resource " + resource); } } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ApplicationInfoService.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ApplicationInfoService.java new file mode 100644 index 0000000000..750a7179fb --- /dev/null +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ApplicationInfoService.java @@ -0,0 +1,76 @@ +package com.provectus.kafka.ui.service; + +import static com.provectus.kafka.ui.model.ApplicationInfoDTO.EnabledFeaturesEnum; + +import com.provectus.kafka.ui.model.ApplicationInfoBuildDTO; +import com.provectus.kafka.ui.model.ApplicationInfoDTO; +import com.provectus.kafka.ui.model.ApplicationInfoLatestReleaseDTO; +import com.provectus.kafka.ui.util.DynamicConfigOperations; +import com.provectus.kafka.ui.util.GithubReleaseInfo; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Properties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.info.BuildProperties; +import org.springframework.boot.info.GitProperties; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +@Service +public class ApplicationInfoService { + + private final GithubReleaseInfo githubReleaseInfo = new GithubReleaseInfo(); + + private final DynamicConfigOperations dynamicConfigOperations; + private final BuildProperties buildProperties; + private final GitProperties gitProperties; + + public ApplicationInfoService(DynamicConfigOperations dynamicConfigOperations, + @Autowired(required = false) BuildProperties buildProperties, + @Autowired(required = false) GitProperties gitProperties) { + this.dynamicConfigOperations = dynamicConfigOperations; + this.buildProperties = Optional.ofNullable(buildProperties).orElse(new BuildProperties(new Properties())); + this.gitProperties = Optional.ofNullable(gitProperties).orElse(new GitProperties(new Properties())); + } + + public ApplicationInfoDTO getApplicationInfo() { + var releaseInfo = githubReleaseInfo.get(); + return new ApplicationInfoDTO() + .build(getBuildInfo(releaseInfo)) + .enabledFeatures(getEnabledFeatures()) + .latestRelease(convert(releaseInfo)); + } + + private ApplicationInfoLatestReleaseDTO convert(GithubReleaseInfo.GithubReleaseDto releaseInfo) { + return new ApplicationInfoLatestReleaseDTO() + .htmlUrl(releaseInfo.html_url()) + .publishedAt(releaseInfo.published_at()) + .versionTag(releaseInfo.tag_name()); + } + + private ApplicationInfoBuildDTO getBuildInfo(GithubReleaseInfo.GithubReleaseDto release) { + return new ApplicationInfoBuildDTO() + .isLatestRelease(release.tag_name() != null && release.tag_name().equals(buildProperties.getVersion())) + .commitId(gitProperties.getShortCommitId()) + .version(buildProperties.getVersion()) + .buildTime(buildProperties.getTime() != null + ? DateTimeFormatter.ISO_INSTANT.format(buildProperties.getTime()) : null); + } + + private List getEnabledFeatures() { + var enabledFeatures = new ArrayList(); + if (dynamicConfigOperations.dynamicConfigEnabled()) { + enabledFeatures.add(EnabledFeaturesEnum.DYNAMIC_CONFIG); + } + return enabledFeatures; + } + + // updating on startup and every hour + @Scheduled(fixedRateString = "${github-release-info-update-rate:3600000}") + public void updateGithubReleaseInfo() { + githubReleaseInfo.refresh().block(); + } + +} diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaConfigSanitizer.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaConfigSanitizer.java index aa26709822..375afb0fef 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaConfigSanitizer.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaConfigSanitizer.java @@ -1,38 +1,58 @@ package com.provectus.kafka.ui.service; +import static java.util.regex.Pattern.CASE_INSENSITIVE; + +import com.google.common.collect.ImmutableList; import java.util.Arrays; -import java.util.HashSet; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; import java.util.stream.Collectors; import org.apache.kafka.common.config.ConfigDef; import org.apache.kafka.common.config.SaslConfigs; import org.apache.kafka.common.config.SslConfigs; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.actuate.endpoint.Sanitizer; import org.springframework.stereotype.Component; @Component -class KafkaConfigSanitizer extends Sanitizer { - private static final List DEFAULT_PATTERNS_TO_SANITIZE = Arrays.asList( - "basic.auth.user.info", /* For Schema Registry credentials */ - "password", "secret", "token", "key", ".*credentials.*", /* General credential patterns */ - "aws.access.*", "aws.secret.*", "aws.session.*" /* AWS-related credential patterns */ - ); +class KafkaConfigSanitizer { + + private static final String SANITIZED_VALUE = "******"; + + private static final String[] REGEX_PARTS = {"*", "$", "^", "+"}; + + private static final List DEFAULT_PATTERNS_TO_SANITIZE = ImmutableList.builder() + .addAll(kafkaConfigKeysToSanitize()) + .add( + "basic.auth.user.info", /* For Schema Registry credentials */ + "password", "secret", "token", "key", ".*credentials.*", /* General credential patterns */ + "aws.access.*", "aws.secret.*", "aws.session.*" /* AWS-related credential patterns */ + ) + .build(); + + private final List sanitizeKeysPatterns; KafkaConfigSanitizer( @Value("${kafka.config.sanitizer.enabled:true}") boolean enabled, @Value("${kafka.config.sanitizer.patterns:}") List patternsToSanitize ) { - if (!enabled) { - setKeysToSanitize(); - } else { - var keysToSanitize = new HashSet<>( - patternsToSanitize.isEmpty() ? DEFAULT_PATTERNS_TO_SANITIZE : patternsToSanitize); - keysToSanitize.addAll(kafkaConfigKeysToSanitize()); - setKeysToSanitize(keysToSanitize.toArray(new String[] {})); - } + this.sanitizeKeysPatterns = enabled + ? compile(patternsToSanitize.isEmpty() ? DEFAULT_PATTERNS_TO_SANITIZE : patternsToSanitize) + : List.of(); + } + + private static List compile(Collection patternStrings) { + return patternStrings.stream() + .map(p -> isRegex(p) + ? Pattern.compile(p, CASE_INSENSITIVE) + : Pattern.compile(".*" + p + "$", CASE_INSENSITIVE)) + .toList(); + } + + private static boolean isRegex(String str) { + return Arrays.stream(REGEX_PARTS).anyMatch(str::contains); } private static Set kafkaConfigKeysToSanitize() { @@ -45,4 +65,17 @@ class KafkaConfigSanitizer extends Sanitizer { .collect(Collectors.toSet()); } + public Object sanitize(String key, Object value) { + if (value == null) { + return null; + } + for (Pattern pattern : sanitizeKeysPatterns) { + if (pattern.matcher(key).matches()) { + return SANITIZED_VALUE; + } + } + return value; + } + + } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaConnectService.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaConnectService.java index 163732fae9..d07ef7ed2d 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaConnectService.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaConnectService.java @@ -225,11 +225,11 @@ public class KafkaConnectService { } public Mono setConnectorConfig(KafkaCluster cluster, String connectName, - String connectorName, Mono requestBody) { + String connectorName, Mono> requestBody) { return api(cluster, connectName) .mono(c -> requestBody - .flatMap(body -> c.setConnectorConfig(connectorName, (Map) body)) + .flatMap(body -> c.setConnectorConfig(connectorName, body)) .map(kafkaConnectMapper::fromClient)); } @@ -298,12 +298,12 @@ public class KafkaConnectService { } public Mono validateConnectorPluginConfig( - KafkaCluster cluster, String connectName, String pluginName, Mono requestBody) { + KafkaCluster cluster, String connectName, String pluginName, Mono> requestBody) { return api(cluster, connectName) .mono(client -> requestBody .flatMap(body -> - client.validateConnectorPluginConfig(pluginName, (Map) body)) + client.validateConnectorPluginConfig(pluginName, body)) .map(kafkaConnectMapper::fromClient) ); } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/MessagesService.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/MessagesService.java index 27f751ac80..4f9f0f59f4 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/MessagesService.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/MessagesService.java @@ -3,9 +3,8 @@ package com.provectus.kafka.ui.service; import com.google.common.util.concurrent.RateLimiter; import com.provectus.kafka.ui.emitter.BackwardRecordEmitter; import com.provectus.kafka.ui.emitter.ForwardRecordEmitter; -import com.provectus.kafka.ui.emitter.MessageFilterStats; import com.provectus.kafka.ui.emitter.MessageFilters; -import com.provectus.kafka.ui.emitter.ResultSizeLimiter; +import com.provectus.kafka.ui.emitter.MessagesProcessing; import com.provectus.kafka.ui.emitter.TailingEmitter; import com.provectus.kafka.ui.exception.TopicNotFoundException; import com.provectus.kafka.ui.exception.ValidationException; @@ -14,9 +13,9 @@ import com.provectus.kafka.ui.model.CreateTopicMessageDTO; import com.provectus.kafka.ui.model.KafkaCluster; import com.provectus.kafka.ui.model.MessageFilterTypeDTO; import com.provectus.kafka.ui.model.SeekDirectionDTO; +import com.provectus.kafka.ui.model.TopicMessageDTO; import com.provectus.kafka.ui.model.TopicMessageEventDTO; import com.provectus.kafka.ui.serde.api.Serde; -import com.provectus.kafka.ui.serdes.ConsumerRecordDeserializer; import com.provectus.kafka.ui.serdes.ProducerRecordCreator; import com.provectus.kafka.ui.util.SslPropertiesUtil; import java.util.List; @@ -162,13 +161,18 @@ public class MessagesService { @Nullable String valueSerde) { java.util.function.Consumer> emitter; - ConsumerRecordDeserializer recordDeserializer = - deserializationService.deserializerFor(cluster, topic, keySerde, valueSerde); + + var processing = new MessagesProcessing( + deserializationService.deserializerFor(cluster, topic, keySerde, valueSerde), + getMsgFilter(query, filterQueryType), + seekDirection == SeekDirectionDTO.TAILING ? null : limit + ); + if (seekDirection.equals(SeekDirectionDTO.FORWARD)) { emitter = new ForwardRecordEmitter( () -> consumerGroupService.createConsumer(cluster), consumerPosition, - recordDeserializer, + processing, cluster.getPollingSettings() ); } else if (seekDirection.equals(SeekDirectionDTO.BACKWARD)) { @@ -176,33 +180,22 @@ public class MessagesService { () -> consumerGroupService.createConsumer(cluster), consumerPosition, limit, - recordDeserializer, + processing, cluster.getPollingSettings() ); } else { emitter = new TailingEmitter( () -> consumerGroupService.createConsumer(cluster), consumerPosition, - recordDeserializer, + processing, cluster.getPollingSettings() ); } - MessageFilterStats filterStats = new MessageFilterStats(); return Flux.create(emitter) - .contextWrite(ctx -> ctx.put(MessageFilterStats.class, filterStats)) - .filter(getMsgFilter(query, filterQueryType, filterStats)) .map(getDataMasker(cluster, topic)) - .takeWhile(createTakeWhilePredicate(seekDirection, limit)) .map(throttleUiPublish(seekDirection)); } - private Predicate createTakeWhilePredicate( - SeekDirectionDTO seekDirection, int limit) { - return seekDirection == SeekDirectionDTO.TAILING - ? evt -> true // no limit for tailing - : new ResultSizeLimiter(limit); - } - private UnaryOperator getDataMasker(KafkaCluster cluster, String topicName) { var keyMasker = cluster.getMasking().getMaskingFunction(topicName, Serde.Target.KEY); var valMasker = cluster.getMasking().getMaskingFunction(topicName, Serde.Target.VALUE); @@ -211,32 +204,18 @@ public class MessagesService { return evt; } return evt.message( - evt.getMessage() - .key(keyMasker.apply(evt.getMessage().getKey())) - .content(valMasker.apply(evt.getMessage().getContent()))); + evt.getMessage() + .key(keyMasker.apply(evt.getMessage().getKey())) + .content(valMasker.apply(evt.getMessage().getContent()))); }; } - private Predicate getMsgFilter(String query, - MessageFilterTypeDTO filterQueryType, - MessageFilterStats filterStats) { + private Predicate getMsgFilter(String query, + MessageFilterTypeDTO filterQueryType) { if (StringUtils.isEmpty(query)) { return evt -> true; } - var messageFilter = MessageFilters.createMsgFilter(query, filterQueryType); - return evt -> { - // we only apply filter for message events - if (evt.getType() == TopicMessageEventDTO.TypeEnum.MESSAGE) { - try { - return messageFilter.test(evt.getMessage()); - } catch (Exception e) { - filterStats.incrementApplyErrors(); - log.trace("Error applying filter '{}' for message {}", query, evt.getMessage()); - return false; - } - } - return true; - }; + return MessageFilters.createMsgFilter(query, filterQueryType); } private UnaryOperator throttleUiPublish(SeekDirectionDTO seekDirection) { diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ReactiveAdminClient.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ReactiveAdminClient.java index 28fcb99f08..53bd5c7faf 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ReactiveAdminClient.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ReactiveAdminClient.java @@ -4,6 +4,7 @@ import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; import static org.apache.kafka.clients.admin.ListOffsetsResult.ListOffsetsResultInfo; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableTable; import com.google.common.collect.Iterables; @@ -514,6 +515,14 @@ public class ReactiveAdminClient implements Closeable { .flatMap(parts -> listOffsetsUnsafe(parts, offsetSpec)); } + /** + * List offset for the specified topics, skipping no-leader partitions. + */ + public Mono> listOffsets(Collection topicDescriptions, + OffsetSpec offsetSpec) { + return listOffsetsUnsafe(filterPartitionsWithLeaderCheck(topicDescriptions, p -> true, false), offsetSpec); + } + private Mono> filterPartitionsWithLeaderCheck(Collection partitions, boolean failOnUnknownLeader) { var targetTopics = partitions.stream().map(TopicPartition::topic).collect(Collectors.toSet()); @@ -523,34 +532,44 @@ public class ReactiveAdminClient implements Closeable { descriptions.values(), partitions::contains, failOnUnknownLeader)); } - private Set filterPartitionsWithLeaderCheck(Collection topicDescriptions, + @VisibleForTesting + static Set filterPartitionsWithLeaderCheck(Collection topicDescriptions, Predicate partitionPredicate, boolean failOnUnknownLeader) { var goodPartitions = new HashSet(); for (TopicDescription description : topicDescriptions) { + var goodTopicPartitions = new ArrayList(); for (TopicPartitionInfo partitionInfo : description.partitions()) { TopicPartition topicPartition = new TopicPartition(description.name(), partitionInfo.partition()); - if (!partitionPredicate.test(topicPartition)) { - continue; + if (partitionInfo.leader() == null) { + if (failOnUnknownLeader) { + throw new ValidationException(String.format("Topic partition %s has no leader", topicPartition)); + } else { + // if ANY of topic partitions has no leader - we have to skip all topic partitions + goodTopicPartitions.clear(); + break; + } } - if (partitionInfo.leader() != null) { - goodPartitions.add(topicPartition); - } else if (failOnUnknownLeader) { - throw new ValidationException(String.format("Topic partition %s has no leader", topicPartition)); + if (partitionPredicate.test(topicPartition)) { + goodTopicPartitions.add(topicPartition); } } + goodPartitions.addAll(goodTopicPartitions); } return goodPartitions; } - // 1. NOTE(!): should only apply for partitions with existing leader, + // 1. NOTE(!): should only apply for partitions from topics where all partitions have leaders, // otherwise AdminClient will try to fetch topic metadata, fail and retry infinitely (until timeout) // 2. NOTE(!): Skips partitions that were not initialized yet // (UnknownTopicOrPartitionException thrown, ex. after topic creation) // 3. TODO: check if it is a bug that AdminClient never throws LeaderNotAvailableException and just retrying instead @KafkaClientInternalsDependant - public Mono> listOffsetsUnsafe(Collection partitions, - OffsetSpec offsetSpec) { + @VisibleForTesting + Mono> listOffsetsUnsafe(Collection partitions, OffsetSpec offsetSpec) { + if (partitions.isEmpty()) { + return Mono.just(Map.of()); + } Function, Mono>> call = parts -> { diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/TopicsService.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/TopicsService.java index 9aaff3e9ef..797c30167b 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/TopicsService.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/TopicsService.java @@ -3,6 +3,7 @@ package com.provectus.kafka.ui.service; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; +import com.google.common.collect.Sets; import com.provectus.kafka.ui.config.ClustersProperties; import com.provectus.kafka.ui.exception.TopicMetadataException; import com.provectus.kafka.ui.exception.TopicNotFoundException; @@ -136,22 +137,14 @@ public class TopicsService { } private Mono getPartitionOffsets(Map - descriptions, + descriptionsMap, ReactiveAdminClient ac) { - var topicPartitions = descriptions.values().stream() - .flatMap(desc -> - desc.partitions().stream() - // list offsets should only be applied to partitions with existing leader - // (see ReactiveAdminClient.listOffsetsUnsafe(..) docs) - .filter(tp -> tp.leader() != null) - .map(p -> new TopicPartition(desc.name(), p.partition()))) - .collect(toList()); - - return ac.listOffsetsUnsafe(topicPartitions, OffsetSpec.earliest()) - .zipWith(ac.listOffsetsUnsafe(topicPartitions, OffsetSpec.latest()), + var descriptions = descriptionsMap.values(); + return ac.listOffsets(descriptions, OffsetSpec.earliest()) + .zipWith(ac.listOffsets(descriptions, OffsetSpec.latest()), (earliest, latest) -> - topicPartitions.stream() - .filter(tp -> earliest.containsKey(tp) && latest.containsKey(tp)) + Sets.intersection(earliest.keySet(), latest.keySet()) + .stream() .map(tp -> Map.entry(tp, new InternalPartitionsOffsets.Offsets( diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/analyze/TopicAnalysisStats.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/analyze/TopicAnalysisStats.java index 2d8e0dc38f..d5b4400807 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/analyze/TopicAnalysisStats.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/analyze/TopicAnalysisStats.java @@ -2,7 +2,7 @@ package com.provectus.kafka.ui.service.analyze; import com.provectus.kafka.ui.model.TopicAnalysisSizeStatsDTO; import com.provectus.kafka.ui.model.TopicAnalysisStatsDTO; -import com.provectus.kafka.ui.model.TopicAnalysisStatsHourlyMsgCountsDTO; +import com.provectus.kafka.ui.model.TopicAnalysisStatsHourlyMsgCountsInnerDTO; import java.time.Duration; import java.time.Instant; import java.util.Comparator; @@ -78,10 +78,10 @@ class TopicAnalysisStats { } } - List toDto() { + List toDto() { return hourlyStats.entrySet().stream() .sorted(Comparator.comparingLong(Map.Entry::getKey)) - .map(e -> new TopicAnalysisStatsHourlyMsgCountsDTO() + .map(e -> new TopicAnalysisStatsHourlyMsgCountsInnerDTO() .hourStart(e.getKey()) .count(e.getValue())) .collect(Collectors.toList()); diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ksql/KsqlApiClient.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ksql/KsqlApiClient.java index fd68add726..e8f4954bf0 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ksql/KsqlApiClient.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ksql/KsqlApiClient.java @@ -52,7 +52,10 @@ public class KsqlApiClient { boolean error; public Optional getColumnValue(List row, String column) { - return Optional.ofNullable(row.get(columnNames.indexOf(column))); + int colIdx = columnNames.indexOf(column); + return colIdx >= 0 + ? Optional.ofNullable(row.get(colIdx)) + : Optional.empty(); } } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ksql/KsqlServiceV2.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ksql/KsqlServiceV2.java index efd7e9ca2e..e8c2a4c65a 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ksql/KsqlServiceV2.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ksql/KsqlServiceV2.java @@ -89,7 +89,14 @@ public class KsqlServiceV2 { .name(resp.getColumnValue(row, "name").map(JsonNode::asText).orElse(null)) .topic(resp.getColumnValue(row, "topic").map(JsonNode::asText).orElse(null)) .keyFormat(resp.getColumnValue(row, "keyFormat").map(JsonNode::asText).orElse(null)) - .valueFormat(resp.getColumnValue(row, "valueFormat").map(JsonNode::asText).orElse(null))) + .valueFormat( + // for old versions (<0.13) "format" column is filled, + // for new version "keyFormat" & "valueFormat" columns should be filled + resp.getColumnValue(row, "valueFormat") + .or(() -> resp.getColumnValue(row, "format")) + .map(JsonNode::asText) + .orElse(null)) + ) .collect(Collectors.toList())); }); } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/AccessControlService.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/AccessControlService.java index ee17d21111..3178feae34 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/AccessControlService.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/AccessControlService.java @@ -21,6 +21,7 @@ import com.provectus.kafka.ui.service.rbac.extractor.GithubAuthorityExtractor; import com.provectus.kafka.ui.service.rbac.extractor.GoogleAuthorityExtractor; import com.provectus.kafka.ui.service.rbac.extractor.LdapAuthorityExtractor; import com.provectus.kafka.ui.service.rbac.extractor.ProviderAuthorityExtractor; +import jakarta.annotation.PostConstruct; import java.util.Collections; import java.util.List; import java.util.Set; @@ -28,7 +29,6 @@ import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.annotation.Nullable; -import javax.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/extractor/CognitoAuthorityExtractor.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/extractor/CognitoAuthorityExtractor.java index a10e0829cc..f7da0a19db 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/extractor/CognitoAuthorityExtractor.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/extractor/CognitoAuthorityExtractor.java @@ -1,9 +1,9 @@ package com.provectus.kafka.ui.service.rbac.extractor; -import com.nimbusds.jose.shaded.json.JSONArray; import com.provectus.kafka.ui.model.rbac.Role; import com.provectus.kafka.ui.model.rbac.provider.Provider; import com.provectus.kafka.ui.service.rbac.AccessControlService; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -44,7 +44,7 @@ public class CognitoAuthorityExtractor implements ProviderAuthorityExtractor { .map(Role::getName) .collect(Collectors.toSet()); - JSONArray groups = principal.getAttribute(COGNITO_GROUPS_ATTRIBUTE_NAME); + List groups = principal.getAttribute(COGNITO_GROUPS_ATTRIBUTE_NAME); if (groups == null) { log.debug("Cognito groups param is not present"); return Mono.just(groupsByUsername); @@ -56,9 +56,8 @@ public class CognitoAuthorityExtractor implements ProviderAuthorityExtractor { .stream() .filter(s -> s.getProvider().equals(Provider.OAUTH_COGNITO)) .filter(s -> s.getType().equals("group")) - .anyMatch(subject -> Stream.of(groups.toArray()) + .anyMatch(subject -> Stream.of(groups) .map(Object::toString) - .distinct() .anyMatch(cognitoGroup -> cognitoGroup.equals(subject.getValue())) )) .map(Role::getName) diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/GithubReleaseInfo.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/GithubReleaseInfo.java new file mode 100644 index 0000000000..2ad0c9c399 --- /dev/null +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/GithubReleaseInfo.java @@ -0,0 +1,53 @@ +package com.provectus.kafka.ui.util; + +import com.google.common.annotations.VisibleForTesting; +import java.time.Duration; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +@Slf4j +public class GithubReleaseInfo { + + private static final String GITHUB_LATEST_RELEASE_RETRIEVAL_URL = + "https://api.github.com/repos/provectus/kafka-ui/releases/latest"; + + private static final Duration GITHUB_API_MAX_WAIT_TIME = Duration.ofSeconds(2); + + public record GithubReleaseDto(String html_url, String tag_name, String published_at) { + + static GithubReleaseDto empty() { + return new GithubReleaseDto(null, null, null); + } + } + + private volatile GithubReleaseDto release = GithubReleaseDto.empty(); + + private final Mono refreshMono; + + public GithubReleaseInfo() { + this(GITHUB_LATEST_RELEASE_RETRIEVAL_URL); + } + + @VisibleForTesting + GithubReleaseInfo(String url) { + this.refreshMono = WebClient.create() + .get() + .uri(url) + .exchangeToMono(resp -> resp.bodyToMono(GithubReleaseDto.class)) + .timeout(GITHUB_API_MAX_WAIT_TIME) + .doOnError(th -> log.trace("Error getting latest github release info", th)) + .onErrorResume(th -> true, th -> Mono.just(GithubReleaseDto.empty())) + .doOnNext(release -> this.release = release) + .then(); + } + + public GithubReleaseDto get() { + return release; + } + + public Mono refresh() { + return refreshMono; + } + +} diff --git a/kafka-ui-api/src/test/java/com/provectus/kafka/ui/AbstractIntegrationTest.java b/kafka-ui-api/src/test/java/com/provectus/kafka/ui/AbstractIntegrationTest.java index a30e45fb3e..dbdfb67fd5 100644 --- a/kafka-ui-api/src/test/java/com/provectus/kafka/ui/AbstractIntegrationTest.java +++ b/kafka-ui-api/src/test/java/com/provectus/kafka/ui/AbstractIntegrationTest.java @@ -16,7 +16,7 @@ import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; -import org.springframework.util.SocketUtils; +import org.springframework.test.util.TestSocketUtils; import org.testcontainers.containers.KafkaContainer; import org.testcontainers.containers.Network; import org.testcontainers.utility.DockerImageName; @@ -61,7 +61,7 @@ public abstract class AbstractIntegrationTest { System.setProperty("kafka.clusters.0.bootstrapServers", kafka.getBootstrapServers()); // List unavailable hosts to verify failover System.setProperty("kafka.clusters.0.schemaRegistry", String.format("http://localhost:%1$s,http://localhost:%1$s,%2$s", - SocketUtils.findAvailableTcpPort(), schemaRegistry.getUrl())); + TestSocketUtils.findAvailableTcpPort(), schemaRegistry.getUrl())); System.setProperty("kafka.clusters.0.kafkaConnect.0.name", "kafka-connect"); System.setProperty("kafka.clusters.0.kafkaConnect.0.userName", "kafka-connect"); System.setProperty("kafka.clusters.0.kafkaConnect.0.password", "kafka-connect"); diff --git a/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/KafkaConfigSanitizerTest.java b/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/KafkaConfigSanitizerTest.java index 232e1d3703..6454cd9f2a 100644 --- a/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/KafkaConfigSanitizerTest.java +++ b/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/KafkaConfigSanitizerTest.java @@ -5,13 +5,12 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.Arrays; import java.util.Collections; import org.junit.jupiter.api.Test; -import org.springframework.boot.actuate.endpoint.Sanitizer; class KafkaConfigSanitizerTest { @Test void doNothingIfEnabledPropertySetToFalse() { - final Sanitizer sanitizer = new KafkaConfigSanitizer(false, Collections.emptyList()); + final var sanitizer = new KafkaConfigSanitizer(false, Collections.emptyList()); assertThat(sanitizer.sanitize("password", "secret")).isEqualTo("secret"); assertThat(sanitizer.sanitize("sasl.jaas.config", "secret")).isEqualTo("secret"); assertThat(sanitizer.sanitize("database.password", "secret")).isEqualTo("secret"); @@ -19,7 +18,7 @@ class KafkaConfigSanitizerTest { @Test void obfuscateCredentials() { - final Sanitizer sanitizer = new KafkaConfigSanitizer(true, Collections.emptyList()); + final var sanitizer = new KafkaConfigSanitizer(true, Collections.emptyList()); assertThat(sanitizer.sanitize("sasl.jaas.config", "secret")).isEqualTo("******"); assertThat(sanitizer.sanitize("consumer.sasl.jaas.config", "secret")).isEqualTo("******"); assertThat(sanitizer.sanitize("producer.sasl.jaas.config", "secret")).isEqualTo("******"); @@ -37,7 +36,7 @@ class KafkaConfigSanitizerTest { @Test void notObfuscateNormalConfigs() { - final Sanitizer sanitizer = new KafkaConfigSanitizer(true, Collections.emptyList()); + final var sanitizer = new KafkaConfigSanitizer(true, Collections.emptyList()); assertThat(sanitizer.sanitize("security.protocol", "SASL_SSL")).isEqualTo("SASL_SSL"); final String[] bootstrapServer = new String[] {"test1:9092", "test2:9092"}; assertThat(sanitizer.sanitize("bootstrap.servers", bootstrapServer)).isEqualTo(bootstrapServer); @@ -45,7 +44,7 @@ class KafkaConfigSanitizerTest { @Test void obfuscateCredentialsWithDefinedPatterns() { - final Sanitizer sanitizer = new KafkaConfigSanitizer(true, Arrays.asList("kafka.ui", ".*test.*")); + final var sanitizer = new KafkaConfigSanitizer(true, Arrays.asList("kafka.ui", ".*test.*")); assertThat(sanitizer.sanitize("consumer.kafka.ui", "secret")).isEqualTo("******"); assertThat(sanitizer.sanitize("this.is.test.credentials", "secret")).isEqualTo("******"); assertThat(sanitizer.sanitize("this.is.not.credential", "not.credential")) diff --git a/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ReactiveAdminClientTest.java b/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ReactiveAdminClientTest.java index 2e302009ac..061c0bea66 100644 --- a/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ReactiveAdminClientTest.java +++ b/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ReactiveAdminClientTest.java @@ -4,8 +4,11 @@ import static com.provectus.kafka.ui.service.ReactiveAdminClient.toMonoWithExcep import static java.util.Objects.requireNonNull; import static org.apache.kafka.clients.admin.ListOffsetsResult.ListOffsetsResultInfo; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.ThrowableAssert.ThrowingCallable; import com.provectus.kafka.ui.AbstractIntegrationTest; +import com.provectus.kafka.ui.exception.ValidationException; import com.provectus.kafka.ui.producer.KafkaTestProducer; import java.time.Duration; import java.util.ArrayList; @@ -22,16 +25,20 @@ import org.apache.kafka.clients.admin.Config; import org.apache.kafka.clients.admin.ConfigEntry; import org.apache.kafka.clients.admin.NewTopic; import org.apache.kafka.clients.admin.OffsetSpec; +import org.apache.kafka.clients.admin.TopicDescription; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.KafkaConsumer; import org.apache.kafka.clients.consumer.OffsetAndMetadata; import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.common.KafkaFuture; +import org.apache.kafka.common.Node; import org.apache.kafka.common.TopicPartition; +import org.apache.kafka.common.TopicPartitionInfo; import org.apache.kafka.common.config.ConfigResource; import org.apache.kafka.common.errors.UnknownTopicOrPartitionException; import org.apache.kafka.common.internals.KafkaFutureImpl; import org.apache.kafka.common.serialization.StringDeserializer; +import org.assertj.core.api.ThrowableAssert; import org.junit.function.ThrowingRunnable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -133,6 +140,56 @@ class ReactiveAdminClientTest extends AbstractIntegrationTest { .verifyComplete(); } + @Test + void filterPartitionsWithLeaderCheckSkipsPartitionsFromTopicWhereSomePartitionsHaveNoLeader() { + var filteredPartitions = ReactiveAdminClient.filterPartitionsWithLeaderCheck( + List.of( + // contains partitions with no leader + new TopicDescription("noLeaderTopic", false, + List.of( + new TopicPartitionInfo(0, new Node(1, "n1", 9092), List.of(), List.of()), + new TopicPartitionInfo(1, null, List.of(), List.of()))), + // should be skipped by predicate + new TopicDescription("skippingByPredicate", false, + List.of( + new TopicPartitionInfo(0, new Node(1, "n1", 9092), List.of(), List.of()))), + // good topic + new TopicDescription("good", false, + List.of( + new TopicPartitionInfo(0, new Node(1, "n1", 9092), List.of(), List.of()), + new TopicPartitionInfo(1, new Node(2, "n2", 9092), List.of(), List.of())) + )), + p -> !p.topic().equals("skippingByPredicate"), + false + ); + + assertThat(filteredPartitions) + .containsExactlyInAnyOrder( + new TopicPartition("good", 0), + new TopicPartition("good", 1) + ); + } + + @Test + void filterPartitionsWithLeaderCheckThrowExceptionIfThereIsSomePartitionsWithoutLeaderAndFlagSet() { + ThrowingCallable call = () -> ReactiveAdminClient.filterPartitionsWithLeaderCheck( + List.of( + // contains partitions with no leader + new TopicDescription("t1", false, + List.of( + new TopicPartitionInfo(0, new Node(1, "n1", 9092), List.of(), List.of()), + new TopicPartitionInfo(1, null, List.of(), List.of()))), + new TopicDescription("t2", false, + List.of( + new TopicPartitionInfo(0, new Node(1, "n1", 9092), List.of(), List.of())) + )), + p -> true, + // setting failOnNoLeader flag + true + ); + assertThatThrownBy(call).isInstanceOf(ValidationException.class); + } + @Test void testListOffsetsUnsafe() { String topic = UUID.randomUUID().toString(); diff --git a/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/RecordEmitterTest.java b/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/RecordEmitterTest.java index e7b9edf834..239f3cf994 100644 --- a/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/RecordEmitterTest.java +++ b/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/RecordEmitterTest.java @@ -9,6 +9,7 @@ import static org.assertj.core.api.Assertions.assertThat; import com.provectus.kafka.ui.AbstractIntegrationTest; import com.provectus.kafka.ui.emitter.BackwardRecordEmitter; import com.provectus.kafka.ui.emitter.ForwardRecordEmitter; +import com.provectus.kafka.ui.emitter.MessagesProcessing; import com.provectus.kafka.ui.emitter.PollingSettings; import com.provectus.kafka.ui.model.ConsumerPosition; import com.provectus.kafka.ui.model.TopicMessageEventDTO; @@ -106,12 +107,16 @@ class RecordEmitterTest extends AbstractIntegrationTest { ); } + private MessagesProcessing createMessagesProcessing() { + return new MessagesProcessing(RECORD_DESERIALIZER, msg -> true, null); + } + @Test void pollNothingOnEmptyTopic() { var forwardEmitter = new ForwardRecordEmitter( this::createConsumer, new ConsumerPosition(BEGINNING, EMPTY_TOPIC, null), - RECORD_DESERIALIZER, + createMessagesProcessing(), PollingSettings.createDefault() ); @@ -119,7 +124,7 @@ class RecordEmitterTest extends AbstractIntegrationTest { this::createConsumer, new ConsumerPosition(BEGINNING, EMPTY_TOPIC, null), 100, - RECORD_DESERIALIZER, + createMessagesProcessing(), PollingSettings.createDefault() ); @@ -141,7 +146,7 @@ class RecordEmitterTest extends AbstractIntegrationTest { var forwardEmitter = new ForwardRecordEmitter( this::createConsumer, new ConsumerPosition(BEGINNING, TOPIC, null), - RECORD_DESERIALIZER, + createMessagesProcessing(), PollingSettings.createDefault() ); @@ -149,7 +154,7 @@ class RecordEmitterTest extends AbstractIntegrationTest { this::createConsumer, new ConsumerPosition(LATEST, TOPIC, null), PARTITIONS * MSGS_PER_PARTITION, - RECORD_DESERIALIZER, + createMessagesProcessing(), PollingSettings.createDefault() ); @@ -170,7 +175,7 @@ class RecordEmitterTest extends AbstractIntegrationTest { var forwardEmitter = new ForwardRecordEmitter( this::createConsumer, new ConsumerPosition(OFFSET, TOPIC, targetOffsets), - RECORD_DESERIALIZER, + createMessagesProcessing(), PollingSettings.createDefault() ); @@ -178,7 +183,7 @@ class RecordEmitterTest extends AbstractIntegrationTest { this::createConsumer, new ConsumerPosition(OFFSET, TOPIC, targetOffsets), PARTITIONS * MSGS_PER_PARTITION, - RECORD_DESERIALIZER, + createMessagesProcessing(), PollingSettings.createDefault() ); @@ -215,7 +220,7 @@ class RecordEmitterTest extends AbstractIntegrationTest { var forwardEmitter = new ForwardRecordEmitter( this::createConsumer, new ConsumerPosition(TIMESTAMP, TOPIC, targetTimestamps), - RECORD_DESERIALIZER, + createMessagesProcessing(), PollingSettings.createDefault() ); @@ -223,7 +228,7 @@ class RecordEmitterTest extends AbstractIntegrationTest { this::createConsumer, new ConsumerPosition(TIMESTAMP, TOPIC, targetTimestamps), PARTITIONS * MSGS_PER_PARTITION, - RECORD_DESERIALIZER, + createMessagesProcessing(), PollingSettings.createDefault() ); @@ -254,7 +259,7 @@ class RecordEmitterTest extends AbstractIntegrationTest { this::createConsumer, new ConsumerPosition(OFFSET, TOPIC, targetOffsets), numMessages, - RECORD_DESERIALIZER, + createMessagesProcessing(), PollingSettings.createDefault() ); @@ -280,7 +285,7 @@ class RecordEmitterTest extends AbstractIntegrationTest { this::createConsumer, new ConsumerPosition(OFFSET, TOPIC, offsets), 100, - RECORD_DESERIALIZER, + createMessagesProcessing(), PollingSettings.createDefault() ); diff --git a/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ksql/KsqlServiceV2Test.java b/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ksql/KsqlServiceV2Test.java index b4a48d3879..afa3700c0f 100644 --- a/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ksql/KsqlServiceV2Test.java +++ b/kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ksql/KsqlServiceV2Test.java @@ -15,7 +15,6 @@ import java.util.concurrent.CopyOnWriteArraySet; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.springframework.util.unit.DataSize; import org.testcontainers.utility.DockerImageName; class KsqlServiceV2Test extends AbstractIntegrationTest { @@ -27,8 +26,6 @@ class KsqlServiceV2Test extends AbstractIntegrationTest { private static final Set STREAMS_TO_DELETE = new CopyOnWriteArraySet<>(); private static final Set TABLES_TO_DELETE = new CopyOnWriteArraySet<>(); - private static final DataSize maxBuffSize = DataSize.ofMegabytes(20); - @BeforeAll static void init() { KSQL_DB.start(); diff --git a/kafka-ui-api/src/test/java/com/provectus/kafka/ui/util/GithubReleaseInfoTest.java b/kafka-ui-api/src/test/java/com/provectus/kafka/ui/util/GithubReleaseInfoTest.java new file mode 100644 index 0000000000..6ec4bb7863 --- /dev/null +++ b/kafka-ui-api/src/test/java/com/provectus/kafka/ui/util/GithubReleaseInfoTest.java @@ -0,0 +1,54 @@ +package com.provectus.kafka.ui.util; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.time.Duration; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import reactor.test.StepVerifier; + +class GithubReleaseInfoTest { + + private final MockWebServer mockWebServer = new MockWebServer(); + + @BeforeEach + void startMockServer() throws IOException { + mockWebServer.start(); + } + + @AfterEach + void stopMockServer() throws IOException { + mockWebServer.close(); + } + + @Test + void test() { + mockWebServer.enqueue(new MockResponse() + .addHeader("content-type: application/json") + .setBody(""" + { + "published_at": "2023-03-09T16:11:31Z", + "tag_name": "v0.6.0", + "html_url": "https://github.com/provectus/kafka-ui/releases/tag/v0.6.0", + "some_unused_prop": "ololo" + } + """)); + var url = mockWebServer.url("repos/provectus/kafka-ui/releases/latest").toString(); + + var infoHolder = new GithubReleaseInfo(url); + infoHolder.refresh().block(); + + var i = infoHolder.get(); + assertThat(i.html_url()) + .isEqualTo("https://github.com/provectus/kafka-ui/releases/tag/v0.6.0"); + assertThat(i.published_at()) + .isEqualTo("2023-03-09T16:11:31Z"); + assertThat(i.tag_name()) + .isEqualTo("v0.6.0"); + } + +} diff --git a/kafka-ui-contract/pom.xml b/kafka-ui-contract/pom.xml index 5f6cb58b7d..f99f20d3d8 100644 --- a/kafka-ui-contract/pom.xml +++ b/kafka-ui-contract/pom.xml @@ -27,20 +27,24 @@ spring-boot-starter-validation - io.swagger - swagger-annotations - ${swagger-annotations.version} + io.swagger.core.v3 + swagger-integration-jakarta + 2.2.8 org.openapitools jackson-databind-nullable - ${jackson-databind-nullable.version} + 0.2.4 - com.google.code.findbugs - jsr305 - 3.0.2 - provided + jakarta.annotation + jakarta.annotation-api + 2.1.1 + + + javax.annotation + javax.annotation-api + 1.3.2 @@ -71,6 +75,7 @@ webclient true java8 + true @@ -80,8 +85,7 @@ generate - ${project.basedir}/src/main/resources/swagger/kafka-ui-api.yaml - + ${project.basedir}/src/main/resources/swagger/kafka-ui-api.yaml ${project.build.directory}/generated-sources/api spring DTO @@ -89,14 +93,12 @@ com.provectus.kafka.ui.model com.provectus.kafka.ui.api kafka-ui-contract - true - true true true true - + true java8 @@ -116,15 +118,13 @@ java false false - com.provectus.kafka.ui.connect.model com.provectus.kafka.ui.connect.api kafka-connect-client - true webclient - + true true java8 @@ -142,15 +142,13 @@ java false false - com.provectus.kafka.ui.sr.model com.provectus.kafka.ui.sr.api kafka-sr-client - true webclient - + true true java8 diff --git a/kafka-ui-contract/src/main/resources/swagger/kafka-ui-api.yaml b/kafka-ui-contract/src/main/resources/swagger/kafka-ui-api.yaml index f0a59c1da5..003ddc2deb 100644 --- a/kafka-ui-contract/src/main/resources/swagger/kafka-ui-api.yaml +++ b/kafka-ui-contract/src/main/resources/swagger/kafka-ui-api.yaml @@ -2021,6 +2021,26 @@ components: type: string enum: - DYNAMIC_CONFIG + build: + type: object + properties: + commitId: + type: string + version: + type: string + buildTime: + type: string + isLatestRelease: + type: boolean + latestRelease: + type: object + properties: + versionTag: + type: string + publishedAt: + type: string + htmlUrl: + type: string Cluster: type: object @@ -2493,6 +2513,10 @@ components: - UNKNOWN ConsumerGroup: + discriminator: + propertyName: inherit + mapping: + details: "#/components/schemas/ConsumerGroupDetails" type: object properties: groupId: diff --git a/kafka-ui-e2e-checks/README.md b/kafka-ui-e2e-checks/README.md index d7f3c77c1f..a33b92739e 100644 --- a/kafka-ui-e2e-checks/README.md +++ b/kafka-ui-e2e-checks/README.md @@ -27,7 +27,7 @@ This repository is for E2E UI automation. ``` git clone https://github.com/provectus/kafka-ui.git cd kafka-ui-e2e-checks -docker pull selenoid/vnc:chrome_86.0 +docker pull selenoid/vnc_chrome:103.0 ``` ### How to run checks @@ -36,6 +36,7 @@ docker pull selenoid/vnc:chrome_86.0 ``` cd kafka-ui +docker-compose -f kafka-ui-e2e-checks/docker/selenoid-local.yaml up -d docker-compose -f documentation/compose/e2e-tests.yaml up -d ``` @@ -51,6 +52,14 @@ docker-compose -f documentation/compose/e2e-tests.yaml up -d -Dbrowser=local ``` +Expected Location of Chrome +``` +Linux: /usr/bin/google-chrome1 +Mac: /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome +Windows XP: %HOMEPATH%\Local Settings\Application Data\Google\Chrome\Application\chrome.exe +Windows Vista and newer: C:\Users%USERNAME%\AppData\Local\Google\Chrome\Application\chrome.exe +``` + ### Qase integration Found instruction for Qase.io integration (for internal use only) at `kafka-ui-e2e-checks/QASE.md` diff --git a/kafka-ui-e2e-checks/docker/selenoid.yaml b/kafka-ui-e2e-checks/docker/selenoid-git.yaml similarity index 61% rename from kafka-ui-e2e-checks/docker/selenoid.yaml rename to kafka-ui-e2e-checks/docker/selenoid-git.yaml index df2f095506..f4c5430f16 100644 --- a/kafka-ui-e2e-checks/docker/selenoid.yaml +++ b/kafka-ui-e2e-checks/docker/selenoid-git.yaml @@ -1,17 +1,19 @@ +--- version: '3' services: + selenoid: network_mode: bridge image: aerokube/selenoid:1.10.7 volumes: - "../selenoid/config:/etc/selenoid" - "/var/run/docker.sock:/var/run/docker.sock" - - "../selenoid/video:/video" + - "../selenoid/video:/opt/selenoid/video" - "../selenoid/logs:/opt/selenoid/logs" environment: - - OVERRIDE_VIDEO_OUTPUT_DIR=video - command: [ "-conf", "/etc/selenoid/browsers.json", "-video-output-dir", "/opt/selenoid/video", "-log-output-dir", "/opt/selenoid/logs" ] + - OVERRIDE_VIDEO_OUTPUT_DIR=../selenoid/video + command: [ "-conf", "/etc/selenoid/browsersGit.json", "-video-output-dir", "/opt/selenoid/video", "-log-output-dir", "/opt/selenoid/logs" ] ports: - "4444:4444" @@ -22,10 +24,10 @@ services: - selenoid ports: - "8081:8080" - command: [ "--selenoid-uri", "http://localhost:4444" ] + command: [ "--selenoid-uri", "http://selenoid:4444" ] selenoid-chrome: network_mode: bridge - image: selenoid/vnc:chrome_96.0 + image: selenoid/vnc_chrome:103.0 extra_hosts: - "host.docker.internal:host-gateway" diff --git a/kafka-ui-e2e-checks/docker/selenoid-local.yaml b/kafka-ui-e2e-checks/docker/selenoid-local.yaml new file mode 100644 index 0000000000..9d7fb8e0be --- /dev/null +++ b/kafka-ui-e2e-checks/docker/selenoid-local.yaml @@ -0,0 +1,33 @@ +--- +version: '3' + +services: + + selenoid: + network_mode: bridge + image: aerokube/selenoid:1.10.7 + volumes: + - "../selenoid/config:/etc/selenoid" + - "/var/run/docker.sock:/var/run/docker.sock" + - "../selenoid/video:/opt/selenoid/video" + - "../selenoid/logs:/opt/selenoid/logs" + environment: + - OVERRIDE_VIDEO_OUTPUT_DIR=../selenoid/video + command: [ "-conf", "/etc/selenoid/browsersLocal.json", "-video-output-dir", "/opt/selenoid/video", "-log-output-dir", "/opt/selenoid/logs" ] + ports: + - "4444:4444" + + selenoid-ui: + network_mode: bridge + image: aerokube/selenoid-ui:latest-release + links: + - selenoid + ports: + - "8081:8080" + command: [ "--selenoid-uri", "http://selenoid:4444" ] + + selenoid-chrome: + network_mode: bridge + image: selenoid/vnc_chrome:103.0 + extra_hosts: + - "host.docker.internal:host-gateway" diff --git a/kafka-ui-e2e-checks/pom.xml b/kafka-ui-e2e-checks/pom.xml index 0b458cf173..c93f6bcabb 100644 --- a/kafka-ui-e2e-checks/pom.xml +++ b/kafka-ui-e2e-checks/pom.xml @@ -17,15 +17,14 @@ 1.17.6 5.2.1 4.8.1 - 6.11.2 + 6.12.3 7.7.0 2.21.0 - 3.0.3 + 3.0.4 1.9.9.1 3.24.2 2.2 - 1.7.36 - 2.3.1 + 2.0.5 3.3.1 @@ -122,6 +121,11 @@ selenium ${testcontainers.version} + + org.projectlombok + lombok + ${org.projectlombok.version} + org.apache.httpcomponents.core5 httpcore5 @@ -132,6 +136,11 @@ httpclient5 ${httpcomponents.version} + + org.seleniumhq.selenium + selenium-http-jdk-client + ${selenium.version} + org.seleniumhq.selenium selenium-http @@ -187,16 +196,6 @@ slf4j-simple ${slf4j.version} - - org.projectlombok - lombok - ${org.projectlombok.version} - - - io.github.cdimascio - dotenv-java - ${dotenv.version} - com.provectus kafka-ui-contract @@ -265,6 +264,37 @@ allure-maven 2.10.0 + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.1.2 + + + com.puppycrawl.tools + checkstyle + 10.3.1 + + + + + checkstyle + validate + + check + + + warning + true + true + true + file:${basedir}/../etc/checkstyle/checkstyle-e2e.xml + file:${basedir}/../etc/checkstyle/apache-header.txt + + + + + + diff --git a/kafka-ui-e2e-checks/selenoid/config/browsersGit.json b/kafka-ui-e2e-checks/selenoid/config/browsersGit.json new file mode 100644 index 0000000000..9e01861615 --- /dev/null +++ b/kafka-ui-e2e-checks/selenoid/config/browsersGit.json @@ -0,0 +1,15 @@ +{ + "chrome": { + "default": "103.0", + "versions": { + "103.0": { + "image": "selenoid/vnc_chrome:103.0", + "hosts": [ + "host.docker.internal:172.17.0.1" + ], + "port": "4444", + "path": "/" + } + } + } +} diff --git a/kafka-ui-e2e-checks/selenoid/config/browsers.json b/kafka-ui-e2e-checks/selenoid/config/browsersLocal.json similarity index 52% rename from kafka-ui-e2e-checks/selenoid/config/browsers.json rename to kafka-ui-e2e-checks/selenoid/config/browsersLocal.json index 6387ffd139..35a494f33d 100644 --- a/kafka-ui-e2e-checks/selenoid/config/browsers.json +++ b/kafka-ui-e2e-checks/selenoid/config/browsersLocal.json @@ -1,9 +1,9 @@ { "chrome": { - "default": "96.0", + "default": "103.0", "versions": { - "96.0": { - "image": "selenoid/vnc_chrome:96.0", + "103.0": { + "image": "selenoid/vnc_chrome:103.0", "port": "4444", "path": "/" } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Connector.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Connector.java index 48088cdf91..493010a3f6 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Connector.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Connector.java @@ -7,5 +7,5 @@ import lombok.experimental.Accessors; @Accessors(chain = true) public class Connector { - private String name, config; + private String name, config; } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Schema.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Schema.java index 19dc44a028..55a6e63112 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Schema.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Schema.java @@ -1,33 +1,34 @@ package com.provectus.kafka.ui.models; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + import com.provectus.kafka.ui.api.model.SchemaType; import lombok.Data; import lombok.experimental.Accessors; -import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; - @Data @Accessors(chain = true) public class Schema { - private String name, valuePath; - private SchemaType type; + private String name, valuePath; + private SchemaType type; - public static Schema createSchemaAvro() { - return new Schema().setName("schema_avro-" + randomAlphabetic(5)) - .setType(SchemaType.AVRO) - .setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_avro_value.json"); - } + public static Schema createSchemaAvro() { + return new Schema().setName("schema_avro-" + randomAlphabetic(5)) + .setType(SchemaType.AVRO) + .setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_avro_value.json"); + } - public static Schema createSchemaJson() { - return new Schema().setName("schema_json-" + randomAlphabetic(5)) - .setType(SchemaType.JSON) - .setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_json_Value.json"); - } + public static Schema createSchemaJson() { + return new Schema().setName("schema_json-" + randomAlphabetic(5)) + .setType(SchemaType.JSON) + .setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_json_Value.json"); + } - public static Schema createSchemaProtobuf() { - return new Schema().setName("schema_protobuf-" + randomAlphabetic(5)) - .setType(SchemaType.PROTOBUF) - .setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_protobuf_value.txt"); - } + public static Schema createSchemaProtobuf() { + return new Schema().setName("schema_protobuf-" + randomAlphabetic(5)) + .setType(SchemaType.PROTOBUF) + .setValuePath( + System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_protobuf_value.txt"); + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Topic.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Topic.java index 21486a93f1..8fb3df086e 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Topic.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Topic.java @@ -11,10 +11,10 @@ import lombok.experimental.Accessors; @Accessors(chain = true) public class Topic { - private String name, timeToRetainData, maxMessageBytes, messageKey, messageContent, customParameterValue; - private int numberOfPartitions; - private CustomParameterType customParameterType; - private CleanupPolicyValue cleanupPolicyValue; - private MaxSizeOnDisk maxSizeOnDisk; - private TimeToRetain timeToRetain; + private String name, timeToRetainData, maxMessageBytes, messageKey, messageValue, customParameterValue; + private int numberOfPartitions; + private CustomParameterType customParameterType; + private CleanupPolicyValue cleanupPolicyValue; + private MaxSizeOnDisk maxSizeOnDisk; + private TimeToRetain timeToRetain; } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/BasePage.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/BasePage.java index 201079fe3b..fb2e0877e2 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/BasePage.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/BasePage.java @@ -1,135 +1,142 @@ package com.provectus.kafka.ui.pages; +import static com.codeborne.selenide.Selenide.$$x; +import static com.codeborne.selenide.Selenide.$x; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.ElementsCollection; import com.codeborne.selenide.SelenideElement; import com.codeborne.selenide.WebDriverRunner; import com.provectus.kafka.ui.pages.panels.enums.MenuItem; import com.provectus.kafka.ui.utilities.WebUtils; +import java.time.Duration; import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.Keys; import org.openqa.selenium.interactions.Actions; -import java.time.Duration; - -import static com.codeborne.selenide.Selenide.$$x; -import static com.codeborne.selenide.Selenide.$x; - @Slf4j public abstract class BasePage extends WebUtils { - protected SelenideElement loadingSpinner = $x("//div[@role='progressbar']"); - protected SelenideElement submitBtn = $x("//button[@type='submit']"); - protected SelenideElement tableGrid = $x("//table"); - protected SelenideElement dotMenuBtn = $x("//button[@aria-label='Dropdown Toggle']"); - protected SelenideElement alertHeader = $x("//div[@role='alert']//div[@role='heading']"); - protected SelenideElement alertMessage = $x("//div[@role='alert']//div[@role='contentinfo']"); - protected SelenideElement confirmationMdl = $x("//div[text()= 'Confirm the action']/.."); - protected SelenideElement confirmBtn = $x("//button[contains(text(),'Confirm')]"); - protected SelenideElement cancelBtn = $x("//button[contains(text(),'Cancel')]"); - protected SelenideElement backBtn = $x("//button[contains(text(),'Back')]"); - protected SelenideElement nextBtn = $x("//button[contains(text(),'Next')]"); - protected ElementsCollection ddlOptions = $$x("//li[@value]"); - protected ElementsCollection gridItems = $$x("//tr[@class]"); - protected String summaryCellLocator = "//div[contains(text(),'%s')]"; - protected String tableElementNameLocator = "//tbody//a[contains(text(),'%s')]"; - protected String columnHeaderLocator = "//table//tr/th//div[text()='%s']"; - protected String pageTitleFromHeader = "//h1[text()='%s']"; - protected String pagePathFromHeader = "//a[text()='%s']/../h1"; + protected SelenideElement loadingSpinner = $x("//div[@role='progressbar']"); + protected SelenideElement submitBtn = $x("//button[@type='submit']"); + protected SelenideElement tableGrid = $x("//table"); + protected SelenideElement searchFld = $x("//input[@type='text'][contains(@id, ':r')]"); + protected SelenideElement dotMenuBtn = $x("//button[@aria-label='Dropdown Toggle']"); + protected SelenideElement alertHeader = $x("//div[@role='alert']//div[@role='heading']"); + protected SelenideElement alertMessage = $x("//div[@role='alert']//div[@role='contentinfo']"); + protected SelenideElement confirmationMdl = $x("//div[text()= 'Confirm the action']/.."); + protected SelenideElement confirmBtn = $x("//button[contains(text(),'Confirm')]"); + protected SelenideElement cancelBtn = $x("//button[contains(text(),'Cancel')]"); + protected SelenideElement backBtn = $x("//button[contains(text(),'Back')]"); + protected SelenideElement nextBtn = $x("//button[contains(text(),'Next')]"); + protected ElementsCollection ddlOptions = $$x("//li[@value]"); + protected ElementsCollection gridItems = $$x("//tr[@class]"); + protected String summaryCellLocator = "//div[contains(text(),'%s')]"; + protected String tableElementNameLocator = "//tbody//a[contains(text(),'%s')]"; + protected String columnHeaderLocator = "//table//tr/th//div[text()='%s']"; + protected String pageTitleFromHeader = "//h1[text()='%s']"; + protected String pagePathFromHeader = "//a[text()='%s']/../h1"; - protected void waitUntilSpinnerDisappear() { - log.debug("\nwaitUntilSpinnerDisappear"); - if (isVisible(loadingSpinner)) { - loadingSpinner.shouldBe(Condition.disappear, Duration.ofSeconds(60)); - } + protected void waitUntilSpinnerDisappear(int... timeoutInSeconds) { + log.debug("\nwaitUntilSpinnerDisappear"); + if (isVisible(loadingSpinner, timeoutInSeconds)) { + loadingSpinner.shouldBe(Condition.disappear, Duration.ofSeconds(60)); + } + } + + protected void searchItem(String tag) { + log.debug("\nsearchItem: {}", tag); + sendKeysAfterClear(searchFld, tag); + searchFld.pressEnter().shouldHave(Condition.value(tag)); + waitUntilSpinnerDisappear(1); + } + + protected SelenideElement getPageTitleFromHeader(MenuItem menuItem) { + return $x(String.format(pageTitleFromHeader, menuItem.getPageTitle())); + } + + protected SelenideElement getPagePathFromHeader(MenuItem menuItem) { + return $x(String.format(pagePathFromHeader, menuItem.getPageTitle())); + } + + protected void clickSubmitBtn() { + clickByJavaScript(submitBtn); + } + + protected void setJsonInputValue(SelenideElement jsonInput, String jsonConfig) { + sendKeysByActions(jsonInput, jsonConfig.replace(" ", "")); + new Actions(WebDriverRunner.getWebDriver()) + .keyDown(Keys.SHIFT) + .sendKeys(Keys.PAGE_DOWN) + .keyUp(Keys.SHIFT) + .sendKeys(Keys.DELETE) + .perform(); + } + + protected SelenideElement getTableElement(String elementName) { + log.debug("\ngetTableElement: {}", elementName); + return $x(String.format(tableElementNameLocator, elementName)); + } + + protected ElementsCollection getDdlOptions() { + return ddlOptions; + } + + protected String getAlertHeader() { + log.debug("\ngetAlertHeader"); + String result = alertHeader.shouldBe(Condition.visible).getText(); + log.debug("-> {}", result); + return result; + } + + protected String getAlertMessage() { + log.debug("\ngetAlertMessage"); + String result = alertMessage.shouldBe(Condition.visible).getText(); + log.debug("-> {}", result); + return result; + } + + protected boolean isAlertVisible(AlertHeader header) { + log.debug("\nisAlertVisible: {}", header.toString()); + boolean result = getAlertHeader().equals(header.toString()); + log.debug("-> {}", result); + return result; + } + + protected boolean isAlertVisible(AlertHeader header, String message) { + log.debug("\nisAlertVisible: {} {}", header, message); + boolean result = isAlertVisible(header) && getAlertMessage().equals(message); + log.debug("-> {}", result); + return result; + } + + protected void clickConfirmButton() { + confirmBtn.shouldBe(Condition.enabled).click(); + confirmBtn.shouldBe(Condition.disappear); + } + + protected void clickCancelButton() { + cancelBtn.shouldBe(Condition.enabled).click(); + cancelBtn.shouldBe(Condition.disappear); + } + + protected boolean isConfirmationModalVisible() { + return isVisible(confirmationMdl); + } + + public enum AlertHeader { + SUCCESS("Success"), + VALIDATION_ERROR("Validation Error"), + BAD_REQUEST("400 Bad Request"); + + private final String value; + + AlertHeader(String value) { + this.value = value; } - protected SelenideElement getPageTitleFromHeader(MenuItem menuItem) { - return $x(String.format(pageTitleFromHeader, menuItem.getPageTitle())); - } - - protected SelenideElement getPagePathFromHeader(MenuItem menuItem) { - return $x(String.format(pagePathFromHeader, menuItem.getPageTitle())); - } - - protected void clickSubmitBtn() { - clickByJavaScript(submitBtn); - } - - protected void setJsonInputValue(SelenideElement jsonInput, String jsonConfig) { - sendKeysByActions(jsonInput, jsonConfig.replace(" ", "")); - new Actions(WebDriverRunner.getWebDriver()) - .keyDown(Keys.SHIFT) - .sendKeys(Keys.PAGE_DOWN) - .keyUp(Keys.SHIFT) - .sendKeys(Keys.DELETE) - .perform(); - } - - protected SelenideElement getTableElement(String elementName) { - log.debug("\ngetTableElement: {}", elementName); - return $x(String.format(tableElementNameLocator, elementName)); - } - - protected ElementsCollection getDdlOptions() { - return ddlOptions; - } - - protected String getAlertHeader() { - log.debug("\ngetAlertHeader"); - String result = alertHeader.shouldBe(Condition.visible).getText(); - log.debug("-> {}", result); - return result; - } - - protected String getAlertMessage() { - log.debug("\ngetAlertMessage"); - String result = alertMessage.shouldBe(Condition.visible).getText(); - log.debug("-> {}", result); - return result; - } - - protected boolean isAlertVisible(AlertHeader header) { - log.debug("\nisAlertVisible: {}", header.toString()); - boolean result = getAlertHeader().equals(header.toString()); - log.debug("-> {}", result); - return result; - } - - protected boolean isAlertVisible(AlertHeader header, String message) { - log.debug("\nisAlertVisible: {} {}", header, message); - boolean result = isAlertVisible(header) && getAlertMessage().equals(message); - log.debug("-> {}", result); - return result; - } - - protected void clickConfirmButton() { - confirmBtn.shouldBe(Condition.enabled).click(); - confirmBtn.shouldBe(Condition.disappear); - } - - protected void clickCancelButton() { - cancelBtn.shouldBe(Condition.enabled).click(); - cancelBtn.shouldBe(Condition.disappear); - } - - protected boolean isConfirmationModalVisible() { - return isVisible(confirmationMdl); - } - - public enum AlertHeader { - SUCCESS("Success"), - VALIDATION_ERROR("Validation Error"), - BAD_REQUEST("400 Bad Request"); - - private final String value; - - AlertHeader(String value) { - this.value = value; - } - - public String toString() { - return value; - } + public String toString() { + return value; } + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersConfigTab.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersConfigTab.java index 7b37d6709c..f358614dc8 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersConfigTab.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersConfigTab.java @@ -1,41 +1,40 @@ package com.provectus.kafka.ui.pages.brokers; +import static com.codeborne.selenide.Selenide.$$x; +import static com.codeborne.selenide.Selenide.$x; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; - import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.codeborne.selenide.Selenide.$$x; -import static com.codeborne.selenide.Selenide.$x; - public class BrokersConfigTab extends BasePage { - protected List editBtn = $$x("//button[@aria-label='editAction']"); - protected SelenideElement searchByKeyField = $x("//input[@placeholder='Search by Key']"); + protected List editBtn = $$x("//button[@aria-label='editAction']"); + protected SelenideElement searchByKeyField = $x("//input[@placeholder='Search by Key']"); - @Step - public BrokersConfigTab waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - searchByKeyField.shouldBe(Condition.visible); - return this; - } + @Step + public BrokersConfigTab waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + searchByKeyField.shouldBe(Condition.visible); + return this; + } - @Step - public boolean isSearchByKeyVisible() { - return isVisible(searchByKeyField); - } + @Step + public boolean isSearchByKeyVisible() { + return isVisible(searchByKeyField); + } - public List getColumnHeaders() { - return Stream.of("Key", "Value", "Source") - .map(name -> $x(String.format(columnHeaderLocator, name))) - .collect(Collectors.toList()); - } + public List getColumnHeaders() { + return Stream.of("Key", "Value", "Source") + .map(name -> $x(String.format(columnHeaderLocator, name))) + .collect(Collectors.toList()); + } - public List getEditButtons() { - return editBtn; - } + public List getEditButtons() { + return editBtn; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersDetails.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersDetails.java index 8cc3dd98ba..4eca65f1f4 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersDetails.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersDetails.java @@ -1,92 +1,91 @@ package com.provectus.kafka.ui.pages.brokers; +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.$x; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; -import org.openqa.selenium.By; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static com.codeborne.selenide.Selenide.$; -import static com.codeborne.selenide.Selenide.$x; +import org.openqa.selenium.By; public class BrokersDetails extends BasePage { - protected SelenideElement logDirectoriesTab = $x("//a[text()='Log directories']"); - protected SelenideElement metricsTab = $x("//a[text()='Metrics']"); - protected String brokersTabLocator = "//a[text()='%s']"; + protected SelenideElement logDirectoriesTab = $x("//a[text()='Log directories']"); + protected SelenideElement metricsTab = $x("//a[text()='Metrics']"); + protected String brokersTabLocator = "//a[text()='%s']"; - @Step - public BrokersDetails waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - Arrays.asList(logDirectoriesTab, metricsTab).forEach(element -> element.shouldBe(Condition.visible)); - return this; + @Step + public BrokersDetails waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + Arrays.asList(logDirectoriesTab, metricsTab).forEach(element -> element.shouldBe(Condition.visible)); + return this; + } + + @Step + public BrokersDetails openDetailsTab(DetailsTab menu) { + $(By.linkText(menu.toString())).shouldBe(Condition.enabled).click(); + waitUntilSpinnerDisappear(); + return this; + } + + private List getVisibleColumnHeaders() { + return Stream.of("Name", "Topics", "Error", "Partitions") + .map(name -> $x(String.format(columnHeaderLocator, name))) + .collect(Collectors.toList()); + } + + private List getEnabledColumnHeaders() { + return Stream.of("Name", "Error") + .map(name -> $x(String.format(columnHeaderLocator, name))) + .collect(Collectors.toList()); + } + + private List getVisibleSummaryCells() { + return Stream.of("Segment Size", "Segment Count", "Port", "Host") + .map(name -> $x(String.format(summaryCellLocator, name))) + .collect(Collectors.toList()); + } + + private List getDetailsTabs() { + return Stream.of(DetailsTab.values()) + .map(name -> $x(String.format(brokersTabLocator, name))) + .collect(Collectors.toList()); + } + + @Step + public List getAllEnabledElements() { + List enabledElements = new ArrayList<>(getEnabledColumnHeaders()); + enabledElements.addAll(getDetailsTabs()); + return enabledElements; + } + + @Step + public List getAllVisibleElements() { + List visibleElements = new ArrayList<>(getVisibleSummaryCells()); + visibleElements.addAll(getVisibleColumnHeaders()); + visibleElements.addAll(getDetailsTabs()); + return visibleElements; + } + + public enum DetailsTab { + LOG_DIRECTORIES("Log directories"), + CONFIGS("Configs"), + METRICS("Metrics"); + + private final String value; + + DetailsTab(String value) { + this.value = value; } - @Step - public BrokersDetails openDetailsTab(DetailsTab menu) { - $(By.linkText(menu.toString())).shouldBe(Condition.enabled).click(); - waitUntilSpinnerDisappear(); - return this; - } - - private List getVisibleColumnHeaders() { - return Stream.of("Name", "Topics", "Error", "Partitions") - .map(name -> $x(String.format(columnHeaderLocator, name))) - .collect(Collectors.toList()); - } - - private List getEnabledColumnHeaders() { - return Stream.of("Name", "Error") - .map(name -> $x(String.format(columnHeaderLocator, name))) - .collect(Collectors.toList()); - } - - private List getVisibleSummaryCells() { - return Stream.of("Segment Size", "Segment Count", "Port", "Host") - .map(name -> $x(String.format(summaryCellLocator, name))) - .collect(Collectors.toList()); - } - - private List getDetailsTabs() { - return Stream.of(DetailsTab.values()) - .map(name -> $x(String.format(brokersTabLocator, name))) - .collect(Collectors.toList()); - } - - @Step - public List getAllEnabledElements() { - List enabledElements = new ArrayList<>(getEnabledColumnHeaders()); - enabledElements.addAll(getDetailsTabs()); - return enabledElements; - } - - @Step - public List getAllVisibleElements() { - List visibleElements = new ArrayList<>(getVisibleSummaryCells()); - visibleElements.addAll(getVisibleColumnHeaders()); - visibleElements.addAll(getDetailsTabs()); - return visibleElements; - } - - public enum DetailsTab { - LOG_DIRECTORIES("Log directories"), - CONFIGS("Configs"), - METRICS("Metrics"); - - private final String value; - - DetailsTab(String value) { - this.value = value; - } - - public String toString() { - return value; - } + public String toString() { + return value; } + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersList.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersList.java index f1f08c3cf5..50ecdff359 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersList.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersList.java @@ -1,123 +1,122 @@ package com.provectus.kafka.ui.pages.brokers; +import static com.codeborne.selenide.Selenide.$x; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.BROKERS; + import com.codeborne.selenide.CollectionCondition; import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; - import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.codeborne.selenide.Selenide.$x; -import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.BROKERS; - public class BrokersList extends BasePage { - @Step - public BrokersList waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - getPageTitleFromHeader(BROKERS).shouldBe(Condition.visible); - return this; + @Step + public BrokersList waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + getPageTitleFromHeader(BROKERS).shouldBe(Condition.visible); + return this; + } + + @Step + public BrokersList openBroker(int brokerId) { + getBrokerItem(brokerId).openItem(); + return this; + } + + private List getUptimeSummaryCells() { + return Stream.of("Broker Count", "Active Controller", "Version") + .map(name -> $x(String.format(summaryCellLocator, name))) + .collect(Collectors.toList()); + } + + private List getPartitionsSummaryCells() { + return Stream.of("Online", "URP", "In Sync Replicas", "Out Of Sync Replicas") + .map(name -> $x(String.format(summaryCellLocator, name))) + .collect(Collectors.toList()); + } + + @Step + public List getAllVisibleElements() { + List visibleElements = new ArrayList<>(getUptimeSummaryCells()); + visibleElements.addAll(getPartitionsSummaryCells()); + return visibleElements; + } + + private List getEnabledColumnHeaders() { + return Stream.of("Broker ID", "Segment Size", "Segment Count", "Port", "Host") + .map(name -> $x(String.format(columnHeaderLocator, name))) + .collect(Collectors.toList()); + } + + @Step + public List getAllEnabledElements() { + return getEnabledColumnHeaders(); + } + + private List initGridItems() { + List gridItemList = new ArrayList<>(); + gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) + .forEach(item -> gridItemList.add(new BrokersList.BrokerGridItem(item))); + return gridItemList; + } + + @Step + public BrokerGridItem getBrokerItem(int id) { + return initGridItems().stream() + .filter(e -> e.getId() == id) + .findFirst().orElseThrow(); + } + + @Step + public List getAllBrokers() { + return initGridItems(); + } + + public static class BrokerGridItem extends BasePage { + + private final SelenideElement element; + + public BrokerGridItem(SelenideElement element) { + this.element = element; + } + + private SelenideElement getIdElm() { + return element.$x("./td[1]/div/a"); } @Step - public BrokersList openBroker(int brokerId) { - getBrokerItem(brokerId).openItem(); - return this; - } - - private List getUptimeSummaryCells() { - return Stream.of("Broker Count", "Active Controller", "Version") - .map(name -> $x(String.format(summaryCellLocator, name))) - .collect(Collectors.toList()); - } - - private List getPartitionsSummaryCells() { - return Stream.of("Online", "URP", "In Sync Replicas", "Out Of Sync Replicas") - .map(name -> $x(String.format(summaryCellLocator, name))) - .collect(Collectors.toList()); + public int getId() { + return Integer.parseInt(getIdElm().getText().trim()); } @Step - public List getAllVisibleElements() { - List visibleElements = new ArrayList<>(getUptimeSummaryCells()); - visibleElements.addAll(getPartitionsSummaryCells()); - return visibleElements; - } - - private List getEnabledColumnHeaders() { - return Stream.of("Broker ID", "Segment Size", "Segment Count", "Port", "Host") - .map(name -> $x(String.format(columnHeaderLocator, name))) - .collect(Collectors.toList()); + public void openItem() { + getIdElm().click(); } @Step - public List getAllEnabledElements() { - return getEnabledColumnHeaders(); - } - - private List initGridItems() { - List gridItemList = new ArrayList<>(); - gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) - .forEach(item -> gridItemList.add(new BrokersList.BrokerGridItem(item))); - return gridItemList; + public int getSegmentSize() { + return Integer.parseInt(element.$x("./td[2]").getText().trim()); } @Step - public BrokerGridItem getBrokerItem(int id) { - return initGridItems().stream() - .filter(e -> e.getId() == id) - .findFirst().orElseThrow(); + public int getSegmentCount() { + return Integer.parseInt(element.$x("./td[3]").getText().trim()); } @Step - public List getAllBrokers() { - return initGridItems(); + public int getPort() { + return Integer.parseInt(element.$x("./td[4]").getText().trim()); } - public static class BrokerGridItem extends BasePage { - - private final SelenideElement element; - - public BrokerGridItem(SelenideElement element) { - this.element = element; - } - - private SelenideElement getIdElm() { - return element.$x("./td[1]/div/a"); - } - - @Step - public int getId() { - return Integer.parseInt(getIdElm().getText().trim()); - } - - @Step - public void openItem() { - getIdElm().click(); - } - - @Step - public int getSegmentSize() { - return Integer.parseInt(element.$x("./td[2]").getText().trim()); - } - - @Step - public int getSegmentCount() { - return Integer.parseInt(element.$x("./td[3]").getText().trim()); - } - - @Step - public int getPort() { - return Integer.parseInt(element.$x("./td[4]").getText().trim()); - } - - @Step - public String getHost() { - return element.$x("./td[5]").getText().trim(); - } + @Step + public String getHost() { + return element.$x("./td[5]").getText().trim(); } + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorCreateForm.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorCreateForm.java index fbbea0f1c0..0b6b7b5608 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorCreateForm.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorCreateForm.java @@ -1,49 +1,49 @@ package com.provectus.kafka.ui.pages.connectors; +import static com.codeborne.selenide.Selenide.$x; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; -import static com.codeborne.selenide.Selenide.$x; - public class ConnectorCreateForm extends BasePage { - protected SelenideElement nameField = $x("//input[@name='name']"); - protected SelenideElement contentTextArea = $x("//textarea[@class='ace_text-input']"); - protected SelenideElement configField = $x("//div[@id='config']"); + protected SelenideElement nameField = $x("//input[@name='name']"); + protected SelenideElement contentTextArea = $x("//textarea[@class='ace_text-input']"); + protected SelenideElement configField = $x("//div[@id='config']"); - @Step - public ConnectorCreateForm waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - nameField.shouldBe(Condition.visible); - return this; - } + @Step + public ConnectorCreateForm waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + nameField.shouldBe(Condition.visible); + return this; + } - @Step - public ConnectorCreateForm setName(String connectName) { - nameField.shouldBe(Condition.enabled).setValue(connectName); - return this; - } + @Step + public ConnectorCreateForm setName(String connectName) { + nameField.shouldBe(Condition.enabled).setValue(connectName); + return this; + } - @Step - public ConnectorCreateForm setConfig(String configJson) { - configField.shouldBe(Condition.enabled).click(); - setJsonInputValue(contentTextArea, configJson); - return this; - } + @Step + public ConnectorCreateForm setConfig(String configJson) { + configField.shouldBe(Condition.enabled).click(); + setJsonInputValue(contentTextArea, configJson); + return this; + } - @Step - public ConnectorCreateForm setConnectorDetails(String connectName, String configJson) { - setName(connectName); - setConfig(configJson); - return this; - } + @Step + public ConnectorCreateForm setConnectorDetails(String connectName, String configJson) { + setName(connectName); + setConfig(configJson); + return this; + } - @Step - public ConnectorCreateForm clickSubmitButton() { - clickSubmitBtn(); - waitUntilSpinnerDisappear(); - return this; - } + @Step + public ConnectorCreateForm clickSubmitButton() { + clickSubmitBtn(); + waitUntilSpinnerDisappear(); + return this; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorDetails.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorDetails.java index fbe1984ce3..de74f67e1c 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorDetails.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorDetails.java @@ -1,84 +1,84 @@ package com.provectus.kafka.ui.pages.connectors; +import static com.codeborne.selenide.Selenide.$x; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; -import static com.codeborne.selenide.Selenide.$x; - public class ConnectorDetails extends BasePage { - protected SelenideElement deleteBtn = $x("//li/div[contains(text(),'Delete')]"); - protected SelenideElement confirmBtnMdl = $x("//div[@role='dialog']//button[contains(text(),'Confirm')]"); - protected SelenideElement contentTextArea = $x("//textarea[@class='ace_text-input']"); - protected SelenideElement taskTab = $x("//a[contains(text(),'Tasks')]"); - protected SelenideElement configTab = $x("//a[contains(text(),'Config')]"); - protected SelenideElement configField = $x("//div[@id='config']"); - protected String connectorHeaderLocator = "//h1[contains(text(),'%s')]"; + protected SelenideElement deleteBtn = $x("//li/div[contains(text(),'Delete')]"); + protected SelenideElement confirmBtnMdl = $x("//div[@role='dialog']//button[contains(text(),'Confirm')]"); + protected SelenideElement contentTextArea = $x("//textarea[@class='ace_text-input']"); + protected SelenideElement taskTab = $x("//a[contains(text(),'Tasks')]"); + protected SelenideElement configTab = $x("//a[contains(text(),'Config')]"); + protected SelenideElement configField = $x("//div[@id='config']"); + protected String connectorHeaderLocator = "//h1[contains(text(),'%s')]"; - @Step - public ConnectorDetails waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - dotMenuBtn.shouldBe(Condition.visible); - return this; - } + @Step + public ConnectorDetails waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + dotMenuBtn.shouldBe(Condition.visible); + return this; + } - @Step - public ConnectorDetails openConfigTab() { - clickByJavaScript(configTab); - return this; - } + @Step + public ConnectorDetails openConfigTab() { + clickByJavaScript(configTab); + return this; + } - @Step - public ConnectorDetails setConfig(String configJson) { - configField.shouldBe(Condition.enabled).click(); - clearByKeyboard(contentTextArea); - contentTextArea.setValue(configJson); - configField.shouldBe(Condition.enabled).click(); - return this; - } + @Step + public ConnectorDetails setConfig(String configJson) { + configField.shouldBe(Condition.enabled).click(); + clearByKeyboard(contentTextArea); + contentTextArea.setValue(configJson); + configField.shouldBe(Condition.enabled).click(); + return this; + } - @Step - public ConnectorDetails clickSubmitButton() { - clickSubmitBtn(); - return this; - } + @Step + public ConnectorDetails clickSubmitButton() { + clickSubmitBtn(); + return this; + } - @Step - public ConnectorDetails openDotMenu() { - clickByJavaScript(dotMenuBtn); - return this; - } + @Step + public ConnectorDetails openDotMenu() { + clickByJavaScript(dotMenuBtn); + return this; + } - @Step - public ConnectorDetails clickDeleteBtn() { - clickByJavaScript(deleteBtn); - return this; - } + @Step + public ConnectorDetails clickDeleteBtn() { + clickByJavaScript(deleteBtn); + return this; + } - @Step - public ConnectorDetails clickConfirmBtn() { - confirmBtnMdl.shouldBe(Condition.enabled).click(); - confirmBtnMdl.shouldBe(Condition.disappear); - return this; - } + @Step + public ConnectorDetails clickConfirmBtn() { + confirmBtnMdl.shouldBe(Condition.enabled).click(); + confirmBtnMdl.shouldBe(Condition.disappear); + return this; + } - @Step - public ConnectorDetails deleteConnector() { - openDotMenu(); - clickDeleteBtn(); - clickConfirmBtn(); - return this; - } + @Step + public ConnectorDetails deleteConnector() { + openDotMenu(); + clickDeleteBtn(); + clickConfirmBtn(); + return this; + } - @Step - public boolean isConnectorHeaderVisible(String connectorName) { - return isVisible($x(String.format(connectorHeaderLocator, connectorName))); - } + @Step + public boolean isConnectorHeaderVisible(String connectorName) { + return isVisible($x(String.format(connectorHeaderLocator, connectorName))); + } - @Step - public boolean isAlertWithMessageVisible(AlertHeader header, String message) { - return isAlertVisible(header, message); - } + @Step + public boolean isAlertWithMessageVisible(AlertHeader header, String message) { + return isAlertVisible(header, message); + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/KafkaConnectList.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/KafkaConnectList.java index 6c672855a6..e4b0d94e64 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/KafkaConnectList.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/KafkaConnectList.java @@ -1,44 +1,44 @@ package com.provectus.kafka.ui.pages.connectors; +import static com.codeborne.selenide.Selenide.$x; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.KAFKA_CONNECT; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; -import static com.codeborne.selenide.Selenide.$x; -import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.KAFKA_CONNECT; - public class KafkaConnectList extends BasePage { - protected SelenideElement createConnectorBtn = $x("//button[contains(text(),'Create Connector')]"); + protected SelenideElement createConnectorBtn = $x("//button[contains(text(),'Create Connector')]"); - public KafkaConnectList() { - tableElementNameLocator = "//tbody//td[contains(text(),'%s')]"; - } + public KafkaConnectList() { + tableElementNameLocator = "//tbody//td[contains(text(),'%s')]"; + } - @Step - public KafkaConnectList waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - getPageTitleFromHeader(KAFKA_CONNECT).shouldBe(Condition.visible); - return this; - } + @Step + public KafkaConnectList waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + getPageTitleFromHeader(KAFKA_CONNECT).shouldBe(Condition.visible); + return this; + } - @Step - public KafkaConnectList clickCreateConnectorBtn() { - clickByJavaScript(createConnectorBtn); - return this; - } + @Step + public KafkaConnectList clickCreateConnectorBtn() { + clickByJavaScript(createConnectorBtn); + return this; + } - @Step - public KafkaConnectList openConnector(String connectorName) { - getTableElement(connectorName).shouldBe(Condition.enabled).click(); - return this; - } + @Step + public KafkaConnectList openConnector(String connectorName) { + getTableElement(connectorName).shouldBe(Condition.enabled).click(); + return this; + } - @Step - public boolean isConnectorVisible(String connectorName) { - tableGrid.shouldBe(Condition.visible); - return isVisible(getTableElement(connectorName)); - } + @Step + public boolean isConnectorVisible(String connectorName) { + tableGrid.shouldBe(Condition.visible); + return isVisible(getTableElement(connectorName)); + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/consumers/ConsumersDetails.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/consumers/ConsumersDetails.java index 240dc613c4..46025927e5 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/consumers/ConsumersDetails.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/consumers/ConsumersDetails.java @@ -1,31 +1,31 @@ package com.provectus.kafka.ui.pages.consumers; +import static com.codeborne.selenide.Selenide.$x; + import com.codeborne.selenide.Condition; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; -import static com.codeborne.selenide.Selenide.$x; - public class ConsumersDetails extends BasePage { - protected String consumerIdHeaderLocator = "//h1[contains(text(),'%s')]"; - protected String topicElementLocator = "//tbody//td//a[text()='%s']"; + protected String consumerIdHeaderLocator = "//h1[contains(text(),'%s')]"; + protected String topicElementLocator = "//tbody//td//a[text()='%s']"; - @Step - public ConsumersDetails waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - tableGrid.shouldBe(Condition.visible); - return this; - } + @Step + public ConsumersDetails waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + tableGrid.shouldBe(Condition.visible); + return this; + } - @Step - public boolean isRedirectedConsumerTitleVisible(String consumerGroupId) { - return isVisible($x(String.format(consumerIdHeaderLocator, consumerGroupId))); - } + @Step + public boolean isRedirectedConsumerTitleVisible(String consumerGroupId) { + return isVisible($x(String.format(consumerIdHeaderLocator, consumerGroupId))); + } - @Step - public boolean isTopicInConsumersDetailsVisible(String topicName) { - tableGrid.shouldBe(Condition.visible); - return isVisible($x(String.format(topicElementLocator, topicName))); - } + @Step + public boolean isTopicInConsumersDetailsVisible(String topicName) { + tableGrid.shouldBe(Condition.visible); + return isVisible($x(String.format(topicElementLocator, topicName))); + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/consumers/ConsumersList.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/consumers/ConsumersList.java index 35ef404344..bc10b8f238 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/consumers/ConsumersList.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/consumers/ConsumersList.java @@ -1,17 +1,17 @@ package com.provectus.kafka.ui.pages.consumers; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.CONSUMERS; + import com.codeborne.selenide.Condition; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; -import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.CONSUMERS; - public class ConsumersList extends BasePage { - @Step - public ConsumersList waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - getPageTitleFromHeader(CONSUMERS).shouldBe(Condition.visible); - return this; - } + @Step + public ConsumersList waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + getPageTitleFromHeader(CONSUMERS).shouldBe(Condition.visible); + return this; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/KsqlDbList.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/KsqlDbList.java deleted file mode 100644 index e80229d931..0000000000 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/KsqlDbList.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.provectus.kafka.ui.pages.ksqlDb; - -import com.codeborne.selenide.CollectionCondition; -import com.codeborne.selenide.Condition; -import com.codeborne.selenide.SelenideElement; -import com.provectus.kafka.ui.pages.BasePage; -import com.provectus.kafka.ui.pages.ksqlDb.enums.KsqlMenuTabs; -import io.qameta.allure.Step; -import org.openqa.selenium.By; - -import java.util.ArrayList; -import java.util.List; - -import static com.codeborne.selenide.Selenide.$; -import static com.codeborne.selenide.Selenide.$x; -import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.KSQL_DB; - -public class KsqlDbList extends BasePage { - - protected SelenideElement executeKsqlBtn = $x("//button[text()='Execute KSQL Request']"); - protected SelenideElement tablesTab = $x("//nav[@role='navigation']/a[text()='Tables']"); - protected SelenideElement streamsTab = $x("//nav[@role='navigation']/a[text()='Streams']"); - - @Step - public KsqlDbList waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - getPageTitleFromHeader(KSQL_DB).shouldBe(Condition.visible); - return this; - } - - @Step - public KsqlDbList clickExecuteKsqlRequestBtn() { - clickByJavaScript(executeKsqlBtn); - return this; - } - - @Step - public KsqlDbList openDetailsTab(KsqlMenuTabs menu) { - $(By.linkText(menu.toString())).shouldBe(Condition.visible).click(); - waitUntilSpinnerDisappear(); - return this; - } - - private List initTablesItems() { - List gridItemList = new ArrayList<>(); - gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) - .forEach(item -> gridItemList.add(new KsqlDbList.KsqlTablesGridItem(item))); - return gridItemList; - } - - @Step - public KsqlDbList.KsqlTablesGridItem getTableByName(String tableName) { - return initTablesItems().stream() - .filter(e -> e.getTableName().equals(tableName)) - .findFirst().orElseThrow(); - } - - private List initStreamsItems() { - List gridItemList = new ArrayList<>(); - gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) - .forEach(item -> gridItemList.add(new KsqlDbList.KsqlStreamsGridItem(item))); - return gridItemList; - } - - @Step - public KsqlDbList.KsqlStreamsGridItem getStreamByName(String streamName) { - return initStreamsItems().stream() - .filter(e -> e.getStreamName().equals(streamName)) - .findFirst().orElseThrow(); - } - - public static class KsqlTablesGridItem extends BasePage { - - private final SelenideElement element; - - public KsqlTablesGridItem(SelenideElement element) { - this.element = element; - } - - @Step - public String getTableName() { - return element.$x("./td[1]").getText().trim(); - } - - @Step - public String getTopicName() { - return element.$x("./td[2]").getText().trim(); - } - - @Step - public String getKeyFormat() { - return element.$x("./td[3]").getText().trim(); - } - - @Step - public String getValueFormat() { - return element.$x("./td[4]").getText().trim(); - } - - @Step - public String getIsWindowed() { - return element.$x("./td[5]").getText().trim(); - } - } - - public static class KsqlStreamsGridItem extends BasePage { - - private final SelenideElement element; - - public KsqlStreamsGridItem(SelenideElement element) { - this.element = element; - } - - @Step - public String getStreamName() { - return element.$x("./td[1]").getText().trim(); - } - - @Step - public String getTopicName() { - return element.$x("./td[2]").getText().trim(); - } - - @Step - public String getKeyFormat() { - return element.$x("./td[3]").getText().trim(); - } - - @Step - public String getValueFormat() { - return element.$x("./td[4]").getText().trim(); - } - - @Step - public String getIsWindowed() { - return element.$x("./td[5]").getText().trim(); - } - } -} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/KsqlQueryForm.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/KsqlQueryForm.java deleted file mode 100644 index df915c0098..0000000000 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/KsqlQueryForm.java +++ /dev/null @@ -1,154 +0,0 @@ -package com.provectus.kafka.ui.pages.ksqlDb; - -import com.codeborne.selenide.CollectionCondition; -import com.codeborne.selenide.Condition; -import com.codeborne.selenide.ElementsCollection; -import com.codeborne.selenide.SelenideElement; -import com.provectus.kafka.ui.pages.BasePage; -import io.qameta.allure.Step; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; - -import static com.codeborne.selenide.Condition.visible; -import static com.codeborne.selenide.Selenide.$$x; -import static com.codeborne.selenide.Selenide.$x; - -public class KsqlQueryForm extends BasePage { - protected SelenideElement clearBtn = $x("//div/button[text()='Clear']"); - protected SelenideElement executeBtn = $x("//div/button[text()='Execute']"); - protected SelenideElement stopQueryBtn = $x("//div/button[text()='Stop query']"); - protected SelenideElement clearResultsBtn = $x("//div/button[text()='Clear results']"); - protected SelenideElement addStreamPropertyBtn = $x("//button[text()='Add Stream Property']"); - protected SelenideElement queryAreaValue = $x("//div[@class='ace_content']"); - protected SelenideElement queryArea = $x("//div[@id='ksql']/textarea[@class='ace_text-input']"); - protected ElementsCollection ksqlGridItems = $$x("//tbody//tr"); - protected ElementsCollection keyField = $$x("//input[@aria-label='key']"); - protected ElementsCollection valueField = $$x("//input[@aria-label='value']"); - - @Step - public KsqlQueryForm waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - executeBtn.shouldBe(Condition.visible); - return this; - } - - @Step - public KsqlQueryForm clickClearBtn() { - clickByJavaScript(clearBtn); - return this; - } - - @Step - public KsqlQueryForm clickExecuteBtn() { - clickByActions(executeBtn); - if (queryAreaValue.getText().contains("EMIT CHANGES;")) { - loadingSpinner.shouldBe(Condition.visible); - } else { - waitUntilSpinnerDisappear(); - } - return this; - } - - @Step - public KsqlQueryForm clickStopQueryBtn() { - clickByActions(stopQueryBtn); - waitUntilSpinnerDisappear(); - return this; - } - - @Step - public KsqlQueryForm clickClearResultsBtn() { - clickByActions(clearResultsBtn); - waitUntilSpinnerDisappear(); - return this; - } - - @Step - public KsqlQueryForm clickAddStreamProperty() { - clickByJavaScript(addStreamPropertyBtn); - return this; - } - - @Step - public KsqlQueryForm setQuery(String query) { - queryAreaValue.shouldBe(Condition.visible).click(); - queryArea.setValue(query); - return this; - } - - @Step - public KsqlQueryForm.KsqlResponseGridItem getTableByName(String name) { - return initItems().stream() - .filter(e -> e.getName().equalsIgnoreCase(name)) - .findFirst().orElseThrow(); - } - - @Step - public boolean areResultsVisible() { - boolean visible = false; - try { - visible = initItems().size() > 0; - } catch (Throwable ignored) { - } - return visible; - } - - private List initItems() { - List gridItemList = new ArrayList<>(); - ksqlGridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) - .forEach(item -> gridItemList.add(new KsqlQueryForm.KsqlResponseGridItem(item))); - return gridItemList; - } - - public static class KsqlResponseGridItem extends BasePage { - - private final SelenideElement element; - - private KsqlResponseGridItem(SelenideElement element) { - this.element = element; - } - - @Step - public String getType() { - return element.$x("./td[1]").getText().trim(); - } - - @Step - public String getName() { - return element.$x("./td[2]").scrollTo().getText().trim(); - } - - @Step - public boolean isVisible() { - boolean isVisible = false; - try { - element.$x("./td[2]").shouldBe(visible, Duration.ofMillis(500)); - isVisible = true; - } catch (Throwable ignored) { - } - return isVisible; - } - - @Step - public String getTopic() { - return element.$x("./td[3]").getText().trim(); - } - - @Step - public String getKeyFormat() { - return element.$x("./td[4]").getText().trim(); - } - - @Step - public String getValueFormat() { - return element.$x("./td[5]").getText().trim(); - } - - @Step - public String getIsWindowed() { - return element.$x("./td[6]").getText().trim(); - } - } -} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/enums/KsqlMenuTabs.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/enums/KsqlMenuTabs.java deleted file mode 100644 index bb719dc0f6..0000000000 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/enums/KsqlMenuTabs.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.provectus.kafka.ui.pages.ksqlDb.enums; - -public enum KsqlMenuTabs { - - TABLES("Table"), - STREAMS("Streams"); - - private final String value; - - KsqlMenuTabs(String value) { - this.value = value; - } - - public String toString() { - return value; - } -} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/enums/KsqlQueryConfig.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/enums/KsqlQueryConfig.java deleted file mode 100644 index 9f85837474..0000000000 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/enums/KsqlQueryConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.provectus.kafka.ui.pages.ksqlDb.enums; - -public enum KsqlQueryConfig { - - SHOW_TABLES("show tables;"), - SHOW_STREAMS("show streams;"), - SELECT_ALL_FROM("SELECT * FROM %s\n" + - "EMIT CHANGES;"); - - private final String query; - - KsqlQueryConfig(String query) { - this.query = query; - } - - public String getQuery() { - return query; - } -} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/KsqlDbList.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/KsqlDbList.java new file mode 100644 index 0000000000..7eb35d52f3 --- /dev/null +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/KsqlDbList.java @@ -0,0 +1,138 @@ +package com.provectus.kafka.ui.pages.ksqldb; + +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.$x; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.KSQL_DB; + +import com.codeborne.selenide.CollectionCondition; +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.SelenideElement; +import com.provectus.kafka.ui.pages.BasePage; +import com.provectus.kafka.ui.pages.ksqldb.enums.KsqlMenuTabs; +import io.qameta.allure.Step; +import java.util.ArrayList; +import java.util.List; +import org.openqa.selenium.By; + +public class KsqlDbList extends BasePage { + + protected SelenideElement executeKsqlBtn = $x("//button[text()='Execute KSQL Request']"); + protected SelenideElement tablesTab = $x("//nav[@role='navigation']/a[text()='Tables']"); + protected SelenideElement streamsTab = $x("//nav[@role='navigation']/a[text()='Streams']"); + + @Step + public KsqlDbList waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + getPageTitleFromHeader(KSQL_DB).shouldBe(Condition.visible); + return this; + } + + @Step + public KsqlDbList clickExecuteKsqlRequestBtn() { + clickByJavaScript(executeKsqlBtn); + return this; + } + + @Step + public KsqlDbList openDetailsTab(KsqlMenuTabs menu) { + $(By.linkText(menu.toString())).shouldBe(Condition.visible).click(); + waitUntilSpinnerDisappear(); + return this; + } + + private List initTablesItems() { + List gridItemList = new ArrayList<>(); + gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) + .forEach(item -> gridItemList.add(new KsqlDbList.KsqlTablesGridItem(item))); + return gridItemList; + } + + @Step + public KsqlDbList.KsqlTablesGridItem getTableByName(String tableName) { + return initTablesItems().stream() + .filter(e -> e.getTableName().equals(tableName)) + .findFirst().orElseThrow(); + } + + private List initStreamsItems() { + List gridItemList = new ArrayList<>(); + gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) + .forEach(item -> gridItemList.add(new KsqlDbList.KsqlStreamsGridItem(item))); + return gridItemList; + } + + @Step + public KsqlDbList.KsqlStreamsGridItem getStreamByName(String streamName) { + return initStreamsItems().stream() + .filter(e -> e.getStreamName().equals(streamName)) + .findFirst().orElseThrow(); + } + + public static class KsqlTablesGridItem extends BasePage { + + private final SelenideElement element; + + public KsqlTablesGridItem(SelenideElement element) { + this.element = element; + } + + @Step + public String getTableName() { + return element.$x("./td[1]").getText().trim(); + } + + @Step + public String getTopicName() { + return element.$x("./td[2]").getText().trim(); + } + + @Step + public String getKeyFormat() { + return element.$x("./td[3]").getText().trim(); + } + + @Step + public String getValueFormat() { + return element.$x("./td[4]").getText().trim(); + } + + @Step + public String getIsWindowed() { + return element.$x("./td[5]").getText().trim(); + } + } + + public static class KsqlStreamsGridItem extends BasePage { + + private final SelenideElement element; + + public KsqlStreamsGridItem(SelenideElement element) { + this.element = element; + } + + @Step + public String getStreamName() { + return element.$x("./td[1]").getText().trim(); + } + + @Step + public String getTopicName() { + return element.$x("./td[2]").getText().trim(); + } + + @Step + public String getKeyFormat() { + return element.$x("./td[3]").getText().trim(); + } + + @Step + public String getValueFormat() { + return element.$x("./td[4]").getText().trim(); + } + + @Step + public String getIsWindowed() { + return element.$x("./td[5]").getText().trim(); + } + } +} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/KsqlQueryForm.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/KsqlQueryForm.java new file mode 100644 index 0000000000..ab24cbe9ab --- /dev/null +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/KsqlQueryForm.java @@ -0,0 +1,153 @@ +package com.provectus.kafka.ui.pages.ksqldb; + +import static com.codeborne.selenide.Condition.visible; +import static com.codeborne.selenide.Selenide.$$x; +import static com.codeborne.selenide.Selenide.$x; + +import com.codeborne.selenide.CollectionCondition; +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.ElementsCollection; +import com.codeborne.selenide.SelenideElement; +import com.provectus.kafka.ui.pages.BasePage; +import io.qameta.allure.Step; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +public class KsqlQueryForm extends BasePage { + protected SelenideElement clearBtn = $x("//div/button[text()='Clear']"); + protected SelenideElement executeBtn = $x("//div/button[text()='Execute']"); + protected SelenideElement stopQueryBtn = $x("//div/button[text()='Stop query']"); + protected SelenideElement clearResultsBtn = $x("//div/button[text()='Clear results']"); + protected SelenideElement addStreamPropertyBtn = $x("//button[text()='Add Stream Property']"); + protected SelenideElement queryAreaValue = $x("//div[@class='ace_content']"); + protected SelenideElement queryArea = $x("//div[@id='ksql']/textarea[@class='ace_text-input']"); + protected ElementsCollection ksqlGridItems = $$x("//tbody//tr"); + protected ElementsCollection keyField = $$x("//input[@aria-label='key']"); + protected ElementsCollection valueField = $$x("//input[@aria-label='value']"); + + @Step + public KsqlQueryForm waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + executeBtn.shouldBe(Condition.visible); + return this; + } + + @Step + public KsqlQueryForm clickClearBtn() { + clickByJavaScript(clearBtn); + return this; + } + + @Step + public KsqlQueryForm clickExecuteBtn() { + clickByActions(executeBtn); + if (queryAreaValue.getText().contains("EMIT CHANGES;")) { + loadingSpinner.shouldBe(Condition.visible); + } else { + waitUntilSpinnerDisappear(); + } + return this; + } + + @Step + public KsqlQueryForm clickStopQueryBtn() { + clickByActions(stopQueryBtn); + waitUntilSpinnerDisappear(); + return this; + } + + @Step + public KsqlQueryForm clickClearResultsBtn() { + clickByActions(clearResultsBtn); + waitUntilSpinnerDisappear(); + return this; + } + + @Step + public KsqlQueryForm clickAddStreamProperty() { + clickByJavaScript(addStreamPropertyBtn); + return this; + } + + @Step + public KsqlQueryForm setQuery(String query) { + queryAreaValue.shouldBe(Condition.visible).click(); + queryArea.setValue(query); + return this; + } + + @Step + public KsqlQueryForm.KsqlResponseGridItem getTableByName(String name) { + return initItems().stream() + .filter(e -> e.getName().equalsIgnoreCase(name)) + .findFirst().orElseThrow(); + } + + @Step + public boolean areResultsVisible() { + boolean visible = false; + try { + visible = initItems().size() > 0; + } catch (Throwable ignored) { + } + return visible; + } + + private List initItems() { + List gridItemList = new ArrayList<>(); + ksqlGridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) + .forEach(item -> gridItemList.add(new KsqlQueryForm.KsqlResponseGridItem(item))); + return gridItemList; + } + + public static class KsqlResponseGridItem extends BasePage { + + private final SelenideElement element; + + private KsqlResponseGridItem(SelenideElement element) { + this.element = element; + } + + @Step + public String getType() { + return element.$x("./td[1]").getText().trim(); + } + + @Step + public String getName() { + return element.$x("./td[2]").scrollTo().getText().trim(); + } + + @Step + public boolean isVisible() { + boolean isVisible = false; + try { + element.$x("./td[2]").shouldBe(visible, Duration.ofMillis(500)); + isVisible = true; + } catch (Throwable ignored) { + } + return isVisible; + } + + @Step + public String getTopic() { + return element.$x("./td[3]").getText().trim(); + } + + @Step + public String getKeyFormat() { + return element.$x("./td[4]").getText().trim(); + } + + @Step + public String getValueFormat() { + return element.$x("./td[5]").getText().trim(); + } + + @Step + public String getIsWindowed() { + return element.$x("./td[6]").getText().trim(); + } + } +} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/enums/KsqlMenuTabs.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/enums/KsqlMenuTabs.java new file mode 100644 index 0000000000..016246edb9 --- /dev/null +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/enums/KsqlMenuTabs.java @@ -0,0 +1,17 @@ +package com.provectus.kafka.ui.pages.ksqldb.enums; + +public enum KsqlMenuTabs { + + TABLES("Table"), + STREAMS("Streams"); + + private final String value; + + KsqlMenuTabs(String value) { + this.value = value; + } + + public String toString() { + return value; + } +} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/enums/KsqlQueryConfig.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/enums/KsqlQueryConfig.java new file mode 100644 index 0000000000..d3cf0ddec2 --- /dev/null +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/enums/KsqlQueryConfig.java @@ -0,0 +1,18 @@ +package com.provectus.kafka.ui.pages.ksqldb.enums; + +public enum KsqlQueryConfig { + + SHOW_TABLES("show tables;"), + SHOW_STREAMS("show streams;"), + SELECT_ALL_FROM("SELECT * FROM %s\n" + "EMIT CHANGES;"); + + private final String query; + + KsqlQueryConfig(String query) { + this.query = query; + } + + public String getQuery() { + return query; + } +} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/models/Stream.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/models/Stream.java similarity index 50% rename from kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/models/Stream.java rename to kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/models/Stream.java index 4030a478c4..3583a24366 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/models/Stream.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/models/Stream.java @@ -1,4 +1,4 @@ -package com.provectus.kafka.ui.pages.ksqlDb.models; +package com.provectus.kafka.ui.pages.ksqldb.models; import lombok.Data; import lombok.experimental.Accessors; @@ -7,5 +7,5 @@ import lombok.experimental.Accessors; @Accessors(chain = true) public class Stream { - private String name, topicName, valueFormat, partitions; + private String name, topicName, valueFormat, partitions; } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/models/Table.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/models/Table.java similarity index 56% rename from kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/models/Table.java rename to kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/models/Table.java index 1856fffd85..96b3d88ba0 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/models/Table.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/models/Table.java @@ -1,4 +1,4 @@ -package com.provectus.kafka.ui.pages.ksqlDb.models; +package com.provectus.kafka.ui.pages.ksqldb.models; import lombok.Data; import lombok.experimental.Accessors; @@ -7,5 +7,5 @@ import lombok.experimental.Accessors; @Accessors(chain = true) public class Table { - private String name, streamName; + private String name, streamName; } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/NaviSideBar.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/NaviSideBar.java index df10360844..ea3cc6ecd1 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/NaviSideBar.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/NaviSideBar.java @@ -1,64 +1,63 @@ package com.provectus.kafka.ui.pages.panels; +import static com.codeborne.selenide.Selenide.$x; +import static com.provectus.kafka.ui.settings.BaseSource.CLUSTER_NAME; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; -import com.provectus.kafka.ui.pages.panels.enums.MenuItem; import com.provectus.kafka.ui.pages.BasePage; +import com.provectus.kafka.ui.pages.panels.enums.MenuItem; import io.qameta.allure.Step; - import java.time.Duration; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.codeborne.selenide.Selenide.$x; -import static com.provectus.kafka.ui.settings.BaseSource.CLUSTER_NAME; - public class NaviSideBar extends BasePage { - protected SelenideElement dashboardMenuItem = $x("//a[@title='Dashboard']"); - protected String sideMenuOptionElementLocator = ".//ul/li[contains(.,'%s')]"; - protected String clusterElementLocator = "//aside/ul/li[contains(.,'%s')]"; + protected SelenideElement dashboardMenuItem = $x("//a[@title='Dashboard']"); + protected String sideMenuOptionElementLocator = ".//ul/li[contains(.,'%s')]"; + protected String clusterElementLocator = "//aside/ul/li[contains(.,'%s')]"; - private SelenideElement expandCluster(String clusterName) { - SelenideElement clusterElement = $x(String.format(clusterElementLocator, clusterName)).shouldBe(Condition.visible); - if (clusterElement.parent().$$x(".//ul").size() == 0) { - clickByActions(clusterElement); - } - return clusterElement; + private SelenideElement expandCluster(String clusterName) { + SelenideElement clusterElement = $x(String.format(clusterElementLocator, clusterName)).shouldBe(Condition.visible); + if (clusterElement.parent().$$x(".//ul").size() == 0) { + clickByActions(clusterElement); } + return clusterElement; + } - @Step - public NaviSideBar waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - dashboardMenuItem.shouldBe(Condition.visible, Duration.ofSeconds(30)); - return this; - } + @Step + public NaviSideBar waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + dashboardMenuItem.shouldBe(Condition.visible, Duration.ofSeconds(30)); + return this; + } - @Step - public String getPagePath(MenuItem menuItem) { - return getPagePathFromHeader(menuItem) - .shouldBe(Condition.visible) - .getText().trim(); - } + @Step + public String getPagePath(MenuItem menuItem) { + return getPagePathFromHeader(menuItem) + .shouldBe(Condition.visible) + .getText().trim(); + } - @Step - public NaviSideBar openSideMenu(String clusterName, MenuItem menuItem) { - clickByActions(expandCluster(clusterName).parent() - .$x(String.format(sideMenuOptionElementLocator, menuItem.getNaviTitle()))); - return this; - } + @Step + public NaviSideBar openSideMenu(String clusterName, MenuItem menuItem) { + clickByActions(expandCluster(clusterName).parent() + .$x(String.format(sideMenuOptionElementLocator, menuItem.getNaviTitle()))); + return this; + } - @Step - public NaviSideBar openSideMenu(MenuItem menuItem) { - openSideMenu(CLUSTER_NAME, menuItem); - return this; - } + @Step + public NaviSideBar openSideMenu(MenuItem menuItem) { + openSideMenu(CLUSTER_NAME, menuItem); + return this; + } - public List getAllMenuButtons() { - expandCluster(CLUSTER_NAME); - return Stream.of(MenuItem.values()) - .map(menuItem -> $x(String.format(sideMenuOptionElementLocator, menuItem.getNaviTitle()))) - .collect(Collectors.toList()); - } + public List getAllMenuButtons() { + expandCluster(CLUSTER_NAME); + return Stream.of(MenuItem.values()) + .map(menuItem -> $x(String.format(sideMenuOptionElementLocator, menuItem.getNaviTitle()))) + .collect(Collectors.toList()); + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/TopPanel.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/TopPanel.java index 77cf71a929..805e5b1ee1 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/TopPanel.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/TopPanel.java @@ -1,26 +1,25 @@ package com.provectus.kafka.ui.pages.panels; -import com.codeborne.selenide.SelenideElement; -import com.provectus.kafka.ui.pages.BasePage; - -import java.util.Arrays; -import java.util.List; - import static com.codeborne.selenide.Selenide.$x; +import com.codeborne.selenide.SelenideElement; +import com.provectus.kafka.ui.pages.BasePage; +import java.util.Arrays; +import java.util.List; + public class TopPanel extends BasePage { - protected SelenideElement kafkaLogo = $x("//a[contains(text(),'UI for Apache Kafka')]"); - protected SelenideElement kafkaVersion = $x("//a[@title='Current commit']"); - protected SelenideElement logOutBtn = $x("//button[contains(text(),'Log out')]"); - protected SelenideElement gitBtn = $x("//a[@href='https://github.com/provectus/kafka-ui']"); - protected SelenideElement discordBtn = $x("//a[contains(@href,'https://discord.com/invite')]"); + protected SelenideElement kafkaLogo = $x("//a[contains(text(),'UI for Apache Kafka')]"); + protected SelenideElement kafkaVersion = $x("//a[@title='Current commit']"); + protected SelenideElement logOutBtn = $x("//button[contains(text(),'Log out')]"); + protected SelenideElement gitBtn = $x("//a[@href='https://github.com/provectus/kafka-ui']"); + protected SelenideElement discordBtn = $x("//a[contains(@href,'https://discord.com/invite')]"); - public List getAllVisibleElements() { - return Arrays.asList(kafkaLogo, kafkaVersion, gitBtn, discordBtn); - } + public List getAllVisibleElements() { + return Arrays.asList(kafkaLogo, kafkaVersion, gitBtn, discordBtn); + } - public List getAllEnabledElements() { - return Arrays.asList(gitBtn, discordBtn, kafkaLogo); - } + public List getAllEnabledElements() { + return Arrays.asList(gitBtn, discordBtn, kafkaLogo); + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/enums/MenuItem.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/enums/MenuItem.java index 6610a8293b..993d6070a0 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/enums/MenuItem.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/enums/MenuItem.java @@ -1,28 +1,28 @@ package com.provectus.kafka.ui.pages.panels.enums; public enum MenuItem { - - DASHBOARD("Dashboard", "Dashboard"), - BROKERS("Brokers", "Brokers"), - TOPICS("Topics", "Topics"), - CONSUMERS("Consumers", "Consumers"), - SCHEMA_REGISTRY("Schema Registry", "Schema Registry"), - KAFKA_CONNECT("Kafka Connect", "Connectors"), - KSQL_DB("KSQL DB", "KSQL DB"); - - private final String naviTitle; - private final String pageTitle; - - MenuItem(String naviTitle, String pageTitle) { - this.naviTitle = naviTitle; - this.pageTitle = pageTitle; - } - - public String getNaviTitle() { - return naviTitle; - } - - public String getPageTitle() { - return pageTitle; - } + + DASHBOARD("Dashboard", "Dashboard"), + BROKERS("Brokers", "Brokers"), + TOPICS("Topics", "Topics"), + CONSUMERS("Consumers", "Consumers"), + SCHEMA_REGISTRY("Schema Registry", "Schema Registry"), + KAFKA_CONNECT("Kafka Connect", "Connectors"), + KSQL_DB("KSQL DB", "KSQL DB"); + + private final String naviTitle; + private final String pageTitle; + + MenuItem(String naviTitle, String pageTitle) { + this.naviTitle = naviTitle; + this.pageTitle = pageTitle; + } + + public String getNaviTitle() { + return naviTitle; + } + + public String getPageTitle() { + return pageTitle; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaCreateForm.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaCreateForm.java index 52bfe0971f..374bb42749 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaCreateForm.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaCreateForm.java @@ -1,5 +1,10 @@ package com.provectus.kafka.ui.pages.schemas; +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.$$x; +import static com.codeborne.selenide.Selenide.$x; +import static org.openqa.selenium.By.id; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.codeborne.selenide.WebDriverRunner; @@ -7,133 +12,130 @@ import com.provectus.kafka.ui.api.model.CompatibilityLevel; import com.provectus.kafka.ui.api.model.SchemaType; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; -import org.openqa.selenium.Keys; -import org.openqa.selenium.interactions.Actions; - import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static com.codeborne.selenide.Selenide.*; -import static org.openqa.selenium.By.id; +import org.openqa.selenium.Keys; +import org.openqa.selenium.interactions.Actions; public class SchemaCreateForm extends BasePage { - protected SelenideElement schemaNameField = $x("//input[@name='subject']"); - protected SelenideElement pageTitle = $x("//h1['Edit']"); - protected SelenideElement schemaTextArea = $x("//textarea[@name='schema']"); - protected SelenideElement newSchemaInput = $("#newSchema [wrap]"); - protected SelenideElement schemaTypeDdl = $x("//ul[@name='schemaType']"); - protected SelenideElement compatibilityLevelList = $x("//ul[@name='compatibilityLevel']"); - protected SelenideElement newSchemaTextArea = $x("//div[@id='newSchema']"); - protected SelenideElement latestSchemaTextArea = $x("//div[@id='latestSchema']"); - protected SelenideElement leftVersionDdl = $(id("left-select")); - protected SelenideElement rightVersionDdl = $(id("right-select")); - protected List visibleMarkers = $$x("//div[@class='ace_scroller']//div[contains(@class,'codeMarker')]"); - protected List elementsCompareVersionDdl = $$x("//ul[@role='listbox']/ul/li"); - protected String ddlElementLocator = "//li[@value='%s']"; + protected SelenideElement schemaNameField = $x("//input[@name='subject']"); + protected SelenideElement pageTitle = $x("//h1['Edit']"); + protected SelenideElement schemaTextArea = $x("//textarea[@name='schema']"); + protected SelenideElement newSchemaInput = $("#newSchema [wrap]"); + protected SelenideElement schemaTypeDdl = $x("//ul[@name='schemaType']"); + protected SelenideElement compatibilityLevelList = $x("//ul[@name='compatibilityLevel']"); + protected SelenideElement newSchemaTextArea = $x("//div[@id='newSchema']"); + protected SelenideElement latestSchemaTextArea = $x("//div[@id='latestSchema']"); + protected SelenideElement leftVersionDdl = $(id("left-select")); + protected SelenideElement rightVersionDdl = $(id("right-select")); + protected List visibleMarkers = + $$x("//div[@class='ace_scroller']//div[contains(@class,'codeMarker')]"); + protected List elementsCompareVersionDdl = $$x("//ul[@role='listbox']/ul/li"); + protected String ddlElementLocator = "//li[@value='%s']"; - @Step - public SchemaCreateForm waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - pageTitle.shouldBe(Condition.visible); - return this; - } + @Step + public SchemaCreateForm waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + pageTitle.shouldBe(Condition.visible); + return this; + } - @Step - public SchemaCreateForm setSubjectName(String name) { - schemaNameField.setValue(name); - return this; - } + @Step + public SchemaCreateForm setSubjectName(String name) { + schemaNameField.setValue(name); + return this; + } - @Step - public SchemaCreateForm setSchemaField(String text) { - schemaTextArea.setValue(text); - return this; - } + @Step + public SchemaCreateForm setSchemaField(String text) { + schemaTextArea.setValue(text); + return this; + } - @Step - public SchemaCreateForm selectSchemaTypeFromDropdown(SchemaType schemaType) { - schemaTypeDdl.shouldBe(Condition.enabled).click(); - $x(String.format(ddlElementLocator, schemaType.getValue())).shouldBe(Condition.visible).click(); - return this; - } + @Step + public SchemaCreateForm selectSchemaTypeFromDropdown(SchemaType schemaType) { + schemaTypeDdl.shouldBe(Condition.enabled).click(); + $x(String.format(ddlElementLocator, schemaType.getValue())).shouldBe(Condition.visible).click(); + return this; + } - @Step - public SchemaCreateForm clickSubmitButton() { - clickSubmitBtn(); - return this; - } + @Step + public SchemaCreateForm clickSubmitButton() { + clickSubmitBtn(); + return this; + } - @Step - public SchemaCreateForm selectCompatibilityLevelFromDropdown(CompatibilityLevel.CompatibilityEnum level) { - compatibilityLevelList.shouldBe(Condition.enabled).click(); - $x(String.format(ddlElementLocator, level.getValue())).shouldBe(Condition.visible).click(); - return this; - } + @Step + public SchemaCreateForm selectCompatibilityLevelFromDropdown(CompatibilityLevel.CompatibilityEnum level) { + compatibilityLevelList.shouldBe(Condition.enabled).click(); + $x(String.format(ddlElementLocator, level.getValue())).shouldBe(Condition.visible).click(); + return this; + } - @Step - public SchemaCreateForm openLeftVersionDdl() { - leftVersionDdl.shouldBe(Condition.enabled).click(); - return this; - } + @Step + public SchemaCreateForm openLeftVersionDdl() { + leftVersionDdl.shouldBe(Condition.enabled).click(); + return this; + } - @Step - public SchemaCreateForm openRightVersionDdl() { - rightVersionDdl.shouldBe(Condition.enabled).click(); - return this; - } + @Step + public SchemaCreateForm openRightVersionDdl() { + rightVersionDdl.shouldBe(Condition.enabled).click(); + return this; + } - @Step - public int getVersionsNumberFromList() { - return elementsCompareVersionDdl.size(); - } + @Step + public int getVersionsNumberFromList() { + return elementsCompareVersionDdl.size(); + } - @Step - public SchemaCreateForm selectVersionFromDropDown(int versionNumberDd) { - $x(String.format(ddlElementLocator, versionNumberDd)).shouldBe(Condition.visible).click(); - return this; - } + @Step + public SchemaCreateForm selectVersionFromDropDown(int versionNumberDd) { + $x(String.format(ddlElementLocator, versionNumberDd)).shouldBe(Condition.visible).click(); + return this; + } - @Step - public int getMarkedLinesNumber() { - return visibleMarkers.size(); - } + @Step + public int getMarkedLinesNumber() { + return visibleMarkers.size(); + } - @Step - public SchemaCreateForm setNewSchemaValue(String configJson) { - newSchemaTextArea.shouldBe(Condition.visible).click(); - newSchemaInput.shouldBe(Condition.enabled); - new Actions(WebDriverRunner.getWebDriver()) - .sendKeys(Keys.PAGE_UP) - .keyDown(Keys.SHIFT) - .sendKeys(Keys.PAGE_DOWN) - .keyUp(Keys.SHIFT) - .sendKeys(Keys.DELETE) - .perform(); - setJsonInputValue(newSchemaInput, configJson); - return this; - } + @Step + public SchemaCreateForm setNewSchemaValue(String configJson) { + newSchemaTextArea.shouldBe(Condition.visible).click(); + newSchemaInput.shouldBe(Condition.enabled); + new Actions(WebDriverRunner.getWebDriver()) + .sendKeys(Keys.PAGE_UP) + .keyDown(Keys.SHIFT) + .sendKeys(Keys.PAGE_DOWN) + .keyUp(Keys.SHIFT) + .sendKeys(Keys.DELETE) + .perform(); + setJsonInputValue(newSchemaInput, configJson); + return this; + } - @Step - public List getAllDetailsPageElements() { - return Stream.of(compatibilityLevelList, newSchemaTextArea, latestSchemaTextArea, submitBtn, schemaTypeDdl) - .collect(Collectors.toList()); - } + @Step + public List getAllDetailsPageElements() { + return Stream.of(compatibilityLevelList, newSchemaTextArea, latestSchemaTextArea, submitBtn, schemaTypeDdl) + .collect(Collectors.toList()); + } - @Step - public boolean isSubmitBtnEnabled() { - return isEnabled(submitBtn); - } + @Step + public boolean isSubmitBtnEnabled() { + return isEnabled(submitBtn); + } - @Step - public boolean isSchemaDropDownEnabled() { - boolean enabled = true; - try { - String attribute = schemaTypeDdl.getAttribute("disabled"); - enabled = false; - } catch (Throwable ignored) { - } - return enabled; + @Step + public boolean isSchemaDropDownEnabled() { + boolean enabled = true; + try { + String attribute = schemaTypeDdl.getAttribute("disabled"); + enabled = false; + } catch (Throwable ignored) { } + return enabled; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaDetails.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaDetails.java index fc7013d46f..11c2d4a7ba 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaDetails.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaDetails.java @@ -1,69 +1,69 @@ package com.provectus.kafka.ui.pages.schemas; +import static com.codeborne.selenide.Selenide.$x; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; -import static com.codeborne.selenide.Selenide.$x; - public class SchemaDetails extends BasePage { - protected SelenideElement actualVersionTextArea = $x("//div[@id='schema']"); - protected SelenideElement compatibilityField = $x("//h4[contains(text(),'Compatibility')]/../p"); - protected SelenideElement editSchemaBtn = $x("//button[contains(text(),'Edit Schema')]"); - protected SelenideElement removeBtn = $x("//*[contains(text(),'Remove')]"); - protected SelenideElement confirmBtn = $x("//div[@role='dialog']//button[contains(text(),'Confirm')]"); - protected SelenideElement schemaTypeField = $x("//h4[contains(text(),'Type')]/../p"); - protected SelenideElement latestVersionField = $x("//h4[contains(text(),'Latest version')]/../p"); - protected SelenideElement compareVersionBtn = $x("//button[text()='Compare Versions']"); - protected String schemaHeaderLocator = "//h1[contains(text(),'%s')]"; + protected SelenideElement actualVersionTextArea = $x("//div[@id='schema']"); + protected SelenideElement compatibilityField = $x("//h4[contains(text(),'Compatibility')]/../p"); + protected SelenideElement editSchemaBtn = $x("//button[contains(text(),'Edit Schema')]"); + protected SelenideElement removeBtn = $x("//*[contains(text(),'Remove')]"); + protected SelenideElement confirmBtn = $x("//div[@role='dialog']//button[contains(text(),'Confirm')]"); + protected SelenideElement schemaTypeField = $x("//h4[contains(text(),'Type')]/../p"); + protected SelenideElement latestVersionField = $x("//h4[contains(text(),'Latest version')]/../p"); + protected SelenideElement compareVersionBtn = $x("//button[text()='Compare Versions']"); + protected String schemaHeaderLocator = "//h1[contains(text(),'%s')]"; - @Step - public SchemaDetails waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - actualVersionTextArea.shouldBe(Condition.visible); - return this; - } + @Step + public SchemaDetails waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + actualVersionTextArea.shouldBe(Condition.visible); + return this; + } - @Step - public String getCompatibility() { - return compatibilityField.getText(); - } + @Step + public String getCompatibility() { + return compatibilityField.getText(); + } - @Step - public boolean isSchemaHeaderVisible(String schemaName) { - return isVisible($x(String.format(schemaHeaderLocator, schemaName))); - } + @Step + public boolean isSchemaHeaderVisible(String schemaName) { + return isVisible($x(String.format(schemaHeaderLocator, schemaName))); + } - @Step - public int getLatestVersion() { - return Integer.parseInt(latestVersionField.getText()); - } + @Step + public int getLatestVersion() { + return Integer.parseInt(latestVersionField.getText()); + } - @Step - public String getSchemaType() { - return schemaTypeField.getText(); - } + @Step + public String getSchemaType() { + return schemaTypeField.getText(); + } - @Step - public SchemaDetails openEditSchema() { - editSchemaBtn.shouldBe(Condition.visible).click(); - return this; - } + @Step + public SchemaDetails openEditSchema() { + editSchemaBtn.shouldBe(Condition.visible).click(); + return this; + } - @Step - public SchemaDetails openCompareVersionMenu() { - compareVersionBtn.shouldBe(Condition.enabled).click(); - return this; - } + @Step + public SchemaDetails openCompareVersionMenu() { + compareVersionBtn.shouldBe(Condition.enabled).click(); + return this; + } - @Step - public SchemaDetails removeSchema() { - clickByJavaScript(dotMenuBtn); - removeBtn.shouldBe(Condition.enabled).click(); - confirmBtn.shouldBe(Condition.visible).click(); - confirmBtn.shouldBe(Condition.disappear); - return this; - } + @Step + public SchemaDetails removeSchema() { + clickByJavaScript(dotMenuBtn); + removeBtn.shouldBe(Condition.enabled).click(); + confirmBtn.shouldBe(Condition.visible).click(); + confirmBtn.shouldBe(Condition.disappear); + return this; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaRegistryList.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaRegistryList.java index 4f06bb995b..f2d2f4b98c 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaRegistryList.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaRegistryList.java @@ -1,42 +1,42 @@ package com.provectus.kafka.ui.pages.schemas; +import static com.codeborne.selenide.Selenide.$x; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.SCHEMA_REGISTRY; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; -import static com.codeborne.selenide.Selenide.$x; -import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.SCHEMA_REGISTRY; - public class SchemaRegistryList extends BasePage { - protected SelenideElement createSchemaBtn = $x("//button[contains(text(),'Create Schema')]"); + protected SelenideElement createSchemaBtn = $x("//button[contains(text(),'Create Schema')]"); - @Step - public SchemaRegistryList waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - getPageTitleFromHeader(SCHEMA_REGISTRY).shouldBe(Condition.visible); - return this; - } + @Step + public SchemaRegistryList waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + getPageTitleFromHeader(SCHEMA_REGISTRY).shouldBe(Condition.visible); + return this; + } - @Step - public SchemaRegistryList clickCreateSchema() { - clickByJavaScript(createSchemaBtn); - return this; - } + @Step + public SchemaRegistryList clickCreateSchema() { + clickByJavaScript(createSchemaBtn); + return this; + } - @Step - public SchemaRegistryList openSchema(String schemaName) { - getTableElement(schemaName) - .shouldBe(Condition.enabled).click(); - return this; - } + @Step + public SchemaRegistryList openSchema(String schemaName) { + getTableElement(schemaName) + .shouldBe(Condition.enabled).click(); + return this; + } - @Step - public boolean isSchemaVisible(String schemaName) { - tableGrid.shouldBe(Condition.visible); - return isVisible(getTableElement(schemaName)); - } + @Step + public boolean isSchemaVisible(String schemaName) { + tableGrid.shouldBe(Condition.visible); + return isVisible(getTableElement(schemaName)); + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/ProduceMessagePanel.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/ProduceMessagePanel.java index 651c514eef..c4e65c65be 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/ProduceMessagePanel.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/ProduceMessagePanel.java @@ -1,57 +1,56 @@ package com.provectus.kafka.ui.pages.topics; +import static com.codeborne.selenide.Selenide.$x; +import static com.codeborne.selenide.Selenide.refresh; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; - import java.util.Arrays; -import static com.codeborne.selenide.Selenide.$x; -import static com.codeborne.selenide.Selenide.refresh; - public class ProduceMessagePanel extends BasePage { - protected SelenideElement keyTextArea = $x("//div[@id='key']/textarea"); - protected SelenideElement contentTextArea = $x("//div[@id='content']/textarea"); - protected SelenideElement headersTextArea = $x("//div[@id='headers']/textarea"); - protected SelenideElement submitBtn = headersTextArea.$x("../../../..//button[@type='submit']"); - protected SelenideElement partitionDdl = $x("//ul[@name='partition']"); - protected SelenideElement keySerdeDdl = $x("//ul[@name='keySerde']"); - protected SelenideElement contentSerdeDdl = $x("//ul[@name='valueSerde']"); + protected SelenideElement keyTextArea = $x("//div[@id='key']/textarea"); + protected SelenideElement valueTextArea = $x("//div[@id='content']/textarea"); + protected SelenideElement headersTextArea = $x("//div[@id='headers']/textarea"); + protected SelenideElement submitBtn = headersTextArea.$x("../../../..//button[@type='submit']"); + protected SelenideElement partitionDdl = $x("//ul[@name='partition']"); + protected SelenideElement keySerdeDdl = $x("//ul[@name='keySerde']"); + protected SelenideElement contentSerdeDdl = $x("//ul[@name='valueSerde']"); - @Step - public ProduceMessagePanel waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - Arrays.asList(partitionDdl, keySerdeDdl, contentSerdeDdl).forEach(element -> element.shouldBe(Condition.visible)); - return this; - } + @Step + public ProduceMessagePanel waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + Arrays.asList(partitionDdl, keySerdeDdl, contentSerdeDdl).forEach(element -> element.shouldBe(Condition.visible)); + return this; + } - @Step - public ProduceMessagePanel setKeyField(String value) { - clearByKeyboard(keyTextArea); - keyTextArea.setValue(value); - return this; - } + @Step + public ProduceMessagePanel setKeyField(String value) { + clearByKeyboard(keyTextArea); + keyTextArea.setValue(value); + return this; + } - @Step - public ProduceMessagePanel setContentFiled(String value) { - clearByKeyboard(contentTextArea); - contentTextArea.setValue(value); - return this; - } + @Step + public ProduceMessagePanel setValueFiled(String value) { + clearByKeyboard(valueTextArea); + valueTextArea.setValue(value); + return this; + } - @Step - public ProduceMessagePanel setHeaderFiled(String value) { - headersTextArea.setValue(value); - return this; - } + @Step + public ProduceMessagePanel setHeadersFld(String value) { + headersTextArea.setValue(value); + return this; + } - @Step - public ProduceMessagePanel submitProduceMessage() { - clickByActions(submitBtn); - submitBtn.shouldBe(Condition.disappear); - refresh(); - return this; - } + @Step + public ProduceMessagePanel submitProduceMessage() { + clickByActions(submitBtn); + submitBtn.shouldBe(Condition.disappear); + refresh(); + return this; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicCreateEditForm.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicCreateEditForm.java index f60bd6d431..57f5930d66 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicCreateEditForm.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicCreateEditForm.java @@ -1,6 +1,15 @@ package com.provectus.kafka.ui.pages.topics; -import com.codeborne.selenide.*; +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.$$; +import static com.codeborne.selenide.Selenide.$x; +import static org.openqa.selenium.By.id; + +import com.codeborne.selenide.ClickOptions; +import com.codeborne.selenide.CollectionCondition; +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.ElementsCollection; +import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import com.provectus.kafka.ui.pages.topics.enums.CleanupPolicyValue; import com.provectus.kafka.ui.pages.topics.enums.CustomParameterType; @@ -8,269 +17,264 @@ import com.provectus.kafka.ui.pages.topics.enums.MaxSizeOnDisk; import com.provectus.kafka.ui.pages.topics.enums.TimeToRetain; import io.qameta.allure.Step; -import static com.codeborne.selenide.Selenide.*; - public class TopicCreateEditForm extends BasePage { - protected SelenideElement timeToRetainField = $x("//input[@id='timeToRetain']"); - protected SelenideElement partitionsField = $x("//input[@name='partitions']"); - protected SelenideElement nameField = $x("//input[@name='name']"); - protected SelenideElement maxMessageBytesField = $x("//input[@name='maxMessageBytes']"); - protected SelenideElement minInSyncReplicasField = $x("//input[@name='minInSyncReplicas']"); - protected SelenideElement cleanUpPolicyDdl = $x("//ul[@id='topicFormCleanupPolicy']"); - protected SelenideElement maxSizeOnDiscDdl = $x("//ul[@id='topicFormRetentionBytes']"); - protected SelenideElement customParameterDdl = $x("//ul[contains(@name,'customParams')]"); - protected SelenideElement deleteCustomParameterBtn = $x("//span[contains(@title,'Delete customParam')]"); - protected SelenideElement addCustomParameterTypeBtn = $x("//button[contains(text(),'Add Custom Parameter')]"); - protected SelenideElement customParameterValueField = $x("//input[@placeholder='Value']"); - protected SelenideElement validationCustomParameterValueMsg = $x("//p[contains(text(),'Value is required')]"); - protected String ddlElementLocator = "//li[@value='%s']"; - protected String btnTimeToRetainLocator = "//button[@class][text()='%s']"; + protected SelenideElement timeToRetainField = $x("//input[@id='timeToRetain']"); + protected SelenideElement partitionsField = $x("//input[@name='partitions']"); + protected SelenideElement nameField = $(id("topicFormName")); + protected SelenideElement maxMessageBytesField = $x("//input[@name='maxMessageBytes']"); + protected SelenideElement minInSyncReplicasField = $x("//input[@name='minInSyncReplicas']"); + protected SelenideElement cleanUpPolicyDdl = $x("//ul[@id='topicFormCleanupPolicy']"); + protected SelenideElement maxSizeOnDiscDdl = $x("//ul[@id='topicFormRetentionBytes']"); + protected SelenideElement customParameterDdl = $x("//ul[contains(@name,'customParams')]"); + protected SelenideElement deleteCustomParameterBtn = $x("//span[contains(@title,'Delete customParam')]"); + protected SelenideElement addCustomParameterTypeBtn = $x("//button[contains(text(),'Add Custom Parameter')]"); + protected SelenideElement customParameterValueField = $x("//input[@placeholder='Value']"); + protected SelenideElement validationCustomParameterValueMsg = $x("//p[contains(text(),'Value is required')]"); + protected String ddlElementLocator = "//li[@value='%s']"; + protected String btnTimeToRetainLocator = "//button[@class][text()='%s']"; - @Step - public TopicCreateEditForm waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - nameField.shouldBe(Condition.visible); - return this; + @Step + public TopicCreateEditForm waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + nameField.shouldBe(Condition.visible); + return this; + } + + public boolean isCreateTopicButtonEnabled() { + return isEnabled(submitBtn); + } + + public boolean isDeleteCustomParameterButtonEnabled() { + return isEnabled(deleteCustomParameterBtn); + } + + public boolean isNameFieldEnabled() { + return isEnabled(nameField); + } + + @Step + public TopicCreateEditForm setTopicName(String topicName) { + sendKeysAfterClear(nameField, topicName); + return this; + } + + @Step + public TopicCreateEditForm setMinInsyncReplicas(Integer minInsyncReplicas) { + minInSyncReplicasField.setValue(minInsyncReplicas.toString()); + return this; + } + + @Step + public TopicCreateEditForm setTimeToRetainDataInMs(Long ms) { + timeToRetainField.setValue(ms.toString()); + return this; + } + + @Step + public TopicCreateEditForm setTimeToRetainDataInMs(String ms) { + timeToRetainField.setValue(ms); + return this; + } + + @Step + public TopicCreateEditForm setMaxSizeOnDiskInGB(MaxSizeOnDisk maxSizeOnDisk) { + maxSizeOnDiscDdl.shouldBe(Condition.visible).click(); + $x(String.format(ddlElementLocator, maxSizeOnDisk.getOptionValue())).shouldBe(Condition.visible).click(); + return this; + } + + @Step + public TopicCreateEditForm clickAddCustomParameterTypeButton() { + addCustomParameterTypeBtn.click(); + return this; + } + + @Step + public TopicCreateEditForm openCustomParameterTypeDdl() { + customParameterDdl.shouldBe(Condition.visible).click(); + ddlOptions.shouldHave(CollectionCondition.sizeGreaterThan(0)); + return this; + } + + @Step + public ElementsCollection getAllDdlOptions() { + return getDdlOptions(); + } + + @Step + public TopicCreateEditForm setCustomParameterType(CustomParameterType customParameterType) { + openCustomParameterTypeDdl(); + $x(String.format(ddlElementLocator, customParameterType.getOptionValue())).shouldBe(Condition.visible).click(); + return this; + } + + @Step + public TopicCreateEditForm clearCustomParameterValue() { + clearByKeyboard(customParameterValueField); + return this; + } + + @Step + public TopicCreateEditForm setNumberOfPartitions(int partitions) { + partitionsField.shouldBe(Condition.enabled).clear(); + partitionsField.sendKeys(String.valueOf(partitions)); + return this; + } + + @Step + public TopicCreateEditForm setTimeToRetainDataByButtons(TimeToRetain timeToRetain) { + $x(String.format(btnTimeToRetainLocator, timeToRetain.getButton())).shouldBe(Condition.enabled).click(); + return this; + } + + @Step + public TopicCreateEditForm selectCleanupPolicy(CleanupPolicyValue cleanupPolicyOptionValue) { + cleanUpPolicyDdl.shouldBe(Condition.visible).click(); + $x(String.format(ddlElementLocator, cleanupPolicyOptionValue.getOptionValue())).shouldBe(Condition.visible).click(); + return this; + } + + @Step + public TopicCreateEditForm selectRetentionBytes(String visibleValue) { + return selectFromDropDownByVisibleText("retentionBytes", visibleValue); + } + + @Step + public TopicCreateEditForm selectRetentionBytes(Long optionValue) { + return selectFromDropDownByOptionValue("retentionBytes", optionValue.toString()); + } + + @Step + public TopicCreateEditForm clickSaveTopicBtn() { + clickSubmitBtn(); + return this; + } + + @Step + public TopicCreateEditForm addCustomParameter(String customParameterName, + String customParameterValue) { + ElementsCollection customParametersElements = + $$("ul[role=listbox][name^=customParams][name$=name]"); + KafkaUiSelectElement kafkaUiSelectElement = null; + if (customParametersElements.size() == 1) { + if ("Select".equals(customParametersElements.first().getText())) { + kafkaUiSelectElement = new KafkaUiSelectElement(customParametersElements.first()); + } + } else { + $$("button") + .find(Condition.exactText("Add Custom Parameter")) + .click(); + customParametersElements = $$("ul[role=listbox][name^=customParams][name$=name]"); + kafkaUiSelectElement = new KafkaUiSelectElement(customParametersElements.last()); + } + if (kafkaUiSelectElement != null) { + kafkaUiSelectElement.selectByVisibleText(customParameterName); + } + $(String.format("input[name=\"customParams.%d.value\"]", customParametersElements.size() - 1)) + .setValue(customParameterValue); + return this; + } + + @Step + public TopicCreateEditForm updateCustomParameter(String customParameterName, + String customParameterValue) { + SelenideElement selenideElement = $$("ul[role=listbox][name^=customParams][name$=name]") + .find(Condition.exactText(customParameterName)); + String name = selenideElement.getAttribute("name"); + if (name != null) { + name = name.substring(0, name.lastIndexOf(".")); + } + $(String.format("input[name^=%s]", name)).setValue(customParameterValue); + return this; + } + + @Step + public String getCleanupPolicy() { + return new KafkaUiSelectElement("cleanupPolicy").getCurrentValue(); + } + + @Step + public String getTimeToRetain() { + return timeToRetainField.getValue(); + } + + @Step + public String getMaxSizeOnDisk() { + return new KafkaUiSelectElement("retentionBytes").getCurrentValue(); + } + + @Step + public String getMaxMessageBytes() { + return maxMessageBytesField.getValue(); + } + + @Step + public TopicCreateEditForm setMaxMessageBytes(Long bytes) { + maxMessageBytesField.setValue(bytes.toString()); + return this; + } + + @Step + public TopicCreateEditForm setMaxMessageBytes(String bytes) { + return setMaxMessageBytes(Long.parseLong(bytes)); + } + + @Step + public boolean isValidationMessageCustomParameterValueVisible() { + return isVisible(validationCustomParameterValueMsg); + } + + @Step + public String getCustomParameterValue() { + return customParameterValueField.getValue(); + } + + private TopicCreateEditForm selectFromDropDownByOptionValue(String dropDownElementName, + String optionValue) { + KafkaUiSelectElement select = new KafkaUiSelectElement(dropDownElementName); + select.selectByOptionValue(optionValue); + return this; + } + + private TopicCreateEditForm selectFromDropDownByVisibleText(String dropDownElementName, + String visibleText) { + KafkaUiSelectElement select = new KafkaUiSelectElement(dropDownElementName); + select.selectByVisibleText(visibleText); + return this; + } + + private static class KafkaUiSelectElement { + + private final SelenideElement selectElement; + + public KafkaUiSelectElement(String selectElementName) { + this.selectElement = $("ul[role=listbox][name=" + selectElementName + "]"); } - public boolean isCreateTopicButtonEnabled() { - return isEnabled(submitBtn); + public KafkaUiSelectElement(SelenideElement selectElement) { + this.selectElement = selectElement; } - public boolean isDeleteCustomParameterButtonEnabled() { - return isEnabled(deleteCustomParameterBtn); + public void selectByOptionValue(String optionValue) { + selectElement.click(); + selectElement + .$$x(".//ul/li[@role='option']") + .find(Condition.attribute("value", optionValue)) + .click(ClickOptions.usingJavaScript()); } - public boolean isNameFieldEnabled() { - return isEnabled(nameField); + public void selectByVisibleText(String visibleText) { + selectElement.click(); + selectElement + .$$("ul>li[role=option]") + .find(Condition.exactText(visibleText)) + .click(); } - @Step - public TopicCreateEditForm setTopicName(String topicName) { - nameField.shouldBe(Condition.enabled).clear(); - if (topicName != null) { - nameField.sendKeys(topicName); - } - return this; - } - - @Step - public TopicCreateEditForm setMinInsyncReplicas(Integer minInsyncReplicas) { - minInSyncReplicasField.setValue(minInsyncReplicas.toString()); - return this; - } - - @Step - public TopicCreateEditForm setTimeToRetainDataInMs(Long ms) { - timeToRetainField.setValue(ms.toString()); - return this; - } - - @Step - public TopicCreateEditForm setTimeToRetainDataInMs(String ms) { - timeToRetainField.setValue(ms); - return this; - } - - @Step - public TopicCreateEditForm setMaxSizeOnDiskInGB(MaxSizeOnDisk MaxSizeOnDisk) { - maxSizeOnDiscDdl.shouldBe(Condition.visible).click(); - $x(String.format(ddlElementLocator, MaxSizeOnDisk.getOptionValue())).shouldBe(Condition.visible).click(); - return this; - } - - @Step - public TopicCreateEditForm clickAddCustomParameterTypeButton() { - addCustomParameterTypeBtn.click(); - return this; - } - - @Step - public TopicCreateEditForm openCustomParameterTypeDdl() { - customParameterDdl.shouldBe(Condition.visible).click(); - ddlOptions.shouldHave(CollectionCondition.sizeGreaterThan(0)); - return this; - } - - @Step - public ElementsCollection getAllDdlOptions() { - return getDdlOptions(); - } - - @Step - public TopicCreateEditForm setCustomParameterType(CustomParameterType customParameterType) { - openCustomParameterTypeDdl(); - $x(String.format(ddlElementLocator, customParameterType.getOptionValue())).shouldBe(Condition.visible).click(); - return this; - } - - @Step - public TopicCreateEditForm clearCustomParameterValue() { - clearByKeyboard(customParameterValueField); - return this; - } - - @Step - public TopicCreateEditForm setNumberOfPartitions(int partitions) { - partitionsField.shouldBe(Condition.enabled).clear(); - partitionsField.sendKeys(String.valueOf(partitions)); - return this; - } - - @Step - public TopicCreateEditForm setTimeToRetainDataByButtons(TimeToRetain timeToRetain) { - $x(String.format(btnTimeToRetainLocator, timeToRetain.getButton())).shouldBe(Condition.enabled).click(); - return this; - } - - @Step - public TopicCreateEditForm selectCleanupPolicy(CleanupPolicyValue cleanupPolicyOptionValue) { - cleanUpPolicyDdl.shouldBe(Condition.visible).click(); - $x(String.format(ddlElementLocator, cleanupPolicyOptionValue.getOptionValue())).shouldBe(Condition.visible).click(); - return this; - } - - @Step - public TopicCreateEditForm selectRetentionBytes(String visibleValue) { - return selectFromDropDownByVisibleText("retentionBytes", visibleValue); - } - - @Step - public TopicCreateEditForm selectRetentionBytes(Long optionValue) { - return selectFromDropDownByOptionValue("retentionBytes", optionValue.toString()); - } - - @Step - public TopicCreateEditForm clickCreateTopicBtn() { - clickSubmitBtn(); - return this; - } - - @Step - public TopicCreateEditForm addCustomParameter(String customParameterName, - String customParameterValue) { - ElementsCollection customParametersElements = - $$("ul[role=listbox][name^=customParams][name$=name]"); - KafkaUISelectElement kafkaUISelectElement = null; - if (customParametersElements.size() == 1) { - if ("Select".equals(customParametersElements.first().getText())) { - kafkaUISelectElement = new KafkaUISelectElement(customParametersElements.first()); - } - } else { - $$("button") - .find(Condition.exactText("Add Custom Parameter")) - .click(); - customParametersElements = $$("ul[role=listbox][name^=customParams][name$=name]"); - kafkaUISelectElement = new KafkaUISelectElement(customParametersElements.last()); - } - if (kafkaUISelectElement != null) { - kafkaUISelectElement.selectByVisibleText(customParameterName); - } - $(String.format("input[name=\"customParams.%d.value\"]", customParametersElements.size() - 1)) - .setValue(customParameterValue); - return this; - } - - @Step - public TopicCreateEditForm updateCustomParameter(String customParameterName, - String customParameterValue) { - SelenideElement selenideElement = $$("ul[role=listbox][name^=customParams][name$=name]") - .find(Condition.exactText(customParameterName)); - String name = selenideElement.getAttribute("name"); - if (name != null) { - name = name.substring(0, name.lastIndexOf(".")); - } - $(String.format("input[name^=%s]", name)).setValue(customParameterValue); - return this; - } - - @Step - public String getCleanupPolicy() { - return new KafkaUISelectElement("cleanupPolicy").getCurrentValue(); - } - - @Step - public String getTimeToRetain() { - return timeToRetainField.getValue(); - } - - @Step - public String getMaxSizeOnDisk() { - return new KafkaUISelectElement("retentionBytes").getCurrentValue(); - } - - @Step - public String getMaxMessageBytes() { - return maxMessageBytesField.getValue(); - } - - @Step - public TopicCreateEditForm setMaxMessageBytes(Long bytes) { - maxMessageBytesField.setValue(bytes.toString()); - return this; - } - - @Step - public TopicCreateEditForm setMaxMessageBytes(String bytes) { - return setMaxMessageBytes(Long.parseLong(bytes)); - } - - @Step - public boolean isValidationMessageCustomParameterValueVisible() { - return isVisible(validationCustomParameterValueMsg); - } - - @Step - public String getCustomParameterValue() { - return customParameterValueField.getValue(); - } - - private TopicCreateEditForm selectFromDropDownByOptionValue(String dropDownElementName, - String optionValue) { - KafkaUISelectElement select = new KafkaUISelectElement(dropDownElementName); - select.selectByOptionValue(optionValue); - return this; - } - - private TopicCreateEditForm selectFromDropDownByVisibleText(String dropDownElementName, - String visibleText) { - KafkaUISelectElement select = new KafkaUISelectElement(dropDownElementName); - select.selectByVisibleText(visibleText); - return this; - } - - private static class KafkaUISelectElement { - - private final SelenideElement selectElement; - - public KafkaUISelectElement(String selectElementName) { - this.selectElement = $("ul[role=listbox][name=" + selectElementName + "]"); - } - - public KafkaUISelectElement(SelenideElement selectElement) { - this.selectElement = selectElement; - } - - public void selectByOptionValue(String optionValue) { - selectElement.click(); - selectElement - .$$x(".//ul/li[@role='option']") - .find(Condition.attribute("value", optionValue)) - .click(ClickOptions.usingJavaScript()); - } - - public void selectByVisibleText(String visibleText) { - selectElement.click(); - selectElement - .$$("ul>li[role=option]") - .find(Condition.exactText(visibleText)) - .click(); - } - - public String getCurrentValue() { - return selectElement.$("li").getText(); - } + public String getCurrentValue() { + return selectElement.$("li").getText(); } + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicDetails.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicDetails.java index a99afd903b..b7d03dcf3a 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicDetails.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicDetails.java @@ -1,463 +1,475 @@ package com.provectus.kafka.ui.pages.topics; +import static com.codeborne.selenide.Selenide.$$x; +import static com.codeborne.selenide.Selenide.$x; +import static com.codeborne.selenide.Selenide.sleep; +import static com.provectus.kafka.ui.pages.topics.TopicDetails.TopicMenu.OVERVIEW; +import static org.testcontainers.shaded.org.apache.commons.lang3.RandomUtils.nextInt; + import com.codeborne.selenide.CollectionCondition; import com.codeborne.selenide.Condition; import com.codeborne.selenide.ElementsCollection; import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; -import org.openqa.selenium.By; - import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; -import java.util.*; - -import static com.codeborne.selenide.Selenide.*; -import static org.testcontainers.shaded.org.apache.commons.lang3.RandomUtils.nextInt; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Objects; public class TopicDetails extends BasePage { - protected SelenideElement clearMessagesBtn = $x(("//div[contains(text(), 'Clear messages')]")); - protected SelenideElement recreateTopicBtn = $x("//div[text()='Recreate Topic']"); - protected SelenideElement messageAmountCell = $x("//tbody/tr/td[5]"); - protected SelenideElement overviewTab = $x("//a[contains(text(),'Overview')]"); - protected SelenideElement messagesTab = $x("//a[contains(text(),'Messages')]"); - protected SelenideElement seekTypeDdl = $x("//ul[@id='selectSeekType']/li"); - protected SelenideElement seekTypeField = $x("//label[text()='Seek Type']//..//div/input"); - protected SelenideElement addFiltersBtn = $x("//button[text()='Add Filters']"); - protected SelenideElement savedFiltersLink = $x("//div[text()='Saved Filters']"); - protected SelenideElement addFilterCodeModalTitle = $x("//label[text()='Filter code']"); - protected SelenideElement addFilterCodeInput = $x("//div[@id='ace-editor']//textarea"); - protected SelenideElement saveThisFilterCheckBoxAddFilterMdl = $x("//input[@name='saveFilter']"); - protected SelenideElement displayNameInputAddFilterMdl = $x("//input[@placeholder='Enter Name']"); - protected SelenideElement cancelBtnAddFilterMdl = $x("//button[text()='Cancel']"); - protected SelenideElement addFilterBtnAddFilterMdl = $x("//button[text()='Add filter']"); - protected SelenideElement addFiltersBtnMessages = $x("//button[text()='Add Filters']"); - protected SelenideElement selectFilterBtnAddFilterMdl = $x("//button[text()='Select filter']"); - protected SelenideElement editSettingsMenu = $x("//li[@role][contains(text(),'Edit settings')]"); - protected SelenideElement removeTopicBtn = $x("//ul[@role='menu']//div[contains(text(),'Remove Topic')]"); - protected SelenideElement produceMessageBtn = $x("//div//button[text()='Produce Message']"); - protected SelenideElement contentMessageTab = $x("//html//div[@id='root']/div/main//table//p"); - protected SelenideElement cleanUpPolicyField = $x("//div[contains(text(),'Clean Up Policy')]/../span/*"); - protected SelenideElement partitionsField = $x("//div[contains(text(),'Partitions')]/../span"); - protected SelenideElement backToCreateFiltersLink = $x("//div[text()='Back To create filters']"); - protected ElementsCollection messageGridItems = $$x("//tbody//tr"); - protected SelenideElement actualCalendarDate = $x("//div[@class='react-datepicker__current-month']"); - protected SelenideElement previousMonthButton = $x("//button[@aria-label='Previous Month']"); - protected SelenideElement nextMonthButton = $x("//button[@aria-label='Next Month']"); - protected SelenideElement calendarTimeFld = $x("//input[@placeholder='Time']"); - protected String dayCellLtr = "//div[@role='option'][contains(text(),'%d')]"; - protected String seekFilterDdlLocator = "//ul[@id='selectSeekType']/ul/li[text()='%s']"; - protected String savedFilterNameLocator = "//div[@role='savedFilter']/div[contains(text(),'%s')]"; - protected String consumerIdLocator = "//a[@title='%s']"; - protected String topicHeaderLocator = "//h1[contains(text(),'%s')]"; - protected String activeFilterNameLocator = "//div[@data-testid='activeSmartFilter'][contains(text(),'%s')]"; - protected String settingsGridValueLocator = "//tbody/tr/td/span[text()='%s']//ancestor::tr/td[2]/span"; + protected SelenideElement clearMessagesBtn = $x(("//div[contains(text(), 'Clear messages')]")); + protected SelenideElement recreateTopicBtn = $x("//div[text()='Recreate Topic']"); + protected SelenideElement messageAmountCell = $x("//tbody/tr/td[5]"); + protected SelenideElement overviewTab = $x("//a[contains(text(),'Overview')]"); + protected SelenideElement messagesTab = $x("//a[contains(text(),'Messages')]"); + protected SelenideElement seekTypeDdl = $x("//ul[@id='selectSeekType']//li"); + protected SelenideElement seekTypeField = $x("//label[text()='Seek Type']//..//div/input"); + protected SelenideElement addFiltersBtn = $x("//button[text()='Add Filters']"); + protected SelenideElement savedFiltersLink = $x("//div[text()='Saved Filters']"); + protected SelenideElement addFilterCodeModalTitle = $x("//label[text()='Filter code']"); + protected SelenideElement addFilterCodeInput = $x("//div[@id='ace-editor']//textarea"); + protected SelenideElement saveThisFilterCheckBoxAddFilterMdl = $x("//input[@name='saveFilter']"); + protected SelenideElement displayNameInputAddFilterMdl = $x("//input[@placeholder='Enter Name']"); + protected SelenideElement cancelBtnAddFilterMdl = $x("//button[text()='Cancel']"); + protected SelenideElement addFilterBtnAddFilterMdl = $x("//button[text()='Add filter']"); + protected SelenideElement addFiltersBtnMessages = $x("//button[text()='Add Filters']"); + protected SelenideElement selectFilterBtnAddFilterMdl = $x("//button[text()='Select filter']"); + protected SelenideElement editSettingsMenu = $x("//li[@role][contains(text(),'Edit settings')]"); + protected SelenideElement removeTopicBtn = $x("//ul[@role='menu']//div[contains(text(),'Remove Topic')]"); + protected SelenideElement produceMessageBtn = $x("//div//button[text()='Produce Message']"); + protected SelenideElement contentMessageTab = $x("//html//div[@id='root']/div/main//table//p"); + protected SelenideElement cleanUpPolicyField = $x("//div[contains(text(),'Clean Up Policy')]/../span/*"); + protected SelenideElement partitionsField = $x("//div[contains(text(),'Partitions')]/../span"); + protected SelenideElement backToCreateFiltersLink = $x("//div[text()='Back To create filters']"); + protected ElementsCollection messageGridItems = $$x("//tbody//tr"); + protected SelenideElement actualCalendarDate = $x("//div[@class='react-datepicker__current-month']"); + protected SelenideElement previousMonthButton = $x("//button[@aria-label='Previous Month']"); + protected SelenideElement nextMonthButton = $x("//button[@aria-label='Next Month']"); + protected SelenideElement calendarTimeFld = $x("//input[@placeholder='Time']"); + protected String detailsTabLtr = "//nav//a[contains(text(),'%s')]"; + protected String dayCellLtr = "//div[@role='option'][contains(text(),'%d')]"; + protected String seekFilterDdlLocator = "//ul[@id='selectSeekType']/ul/li[text()='%s']"; + protected String savedFilterNameLocator = "//div[@role='savedFilter']/div[contains(text(),'%s')]"; + protected String consumerIdLocator = "//a[@title='%s']"; + protected String topicHeaderLocator = "//h1[contains(text(),'%s')]"; + protected String activeFilterNameLocator = "//div[@data-testid='activeSmartFilter'][contains(text(),'%s')]"; + protected String settingsGridValueLocator = "//tbody/tr/td/span[text()='%s']//ancestor::tr/td[2]/span"; - @Step - public TopicDetails waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - overviewTab.shouldBe(Condition.visible); - return this; + @Step + public TopicDetails waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + $x(String.format(detailsTabLtr, OVERVIEW)).shouldBe(Condition.visible); + return this; + } + + @Step + public TopicDetails openDetailsTab(TopicMenu menu) { + $x(String.format(detailsTabLtr, menu.toString())).shouldBe(Condition.enabled).click(); + waitUntilSpinnerDisappear(); + return this; + } + + @Step + public String getSettingsGridValueByKey(String key) { + return $x(String.format(settingsGridValueLocator, key)).scrollTo().shouldBe(Condition.visible).getText(); + } + + @Step + public TopicDetails openDotMenu() { + clickByJavaScript(dotMenuBtn); + return this; + } + + @Step + public boolean isAlertWithMessageVisible(AlertHeader header, String message) { + return isAlertVisible(header, message); + } + + @Step + public TopicDetails clickEditSettingsMenu() { + editSettingsMenu.shouldBe(Condition.visible).click(); + return this; + } + + @Step + public boolean isConfirmationMdlVisible() { + return isConfirmationModalVisible(); + } + + @Step + public TopicDetails clickClearMessagesMenu() { + clearMessagesBtn.shouldBe(Condition.visible).click(); + return this; + } + + @Step + public boolean isClearMessagesMenuEnabled() { + return !Objects.requireNonNull(clearMessagesBtn.shouldBe(Condition.visible) + .$x("./..").getAttribute("class")) + .contains("disabled"); + } + + @Step + public TopicDetails clickRecreateTopicMenu() { + recreateTopicBtn.shouldBe(Condition.visible).click(); + return this; + } + + @Step + public String getCleanUpPolicy() { + return cleanUpPolicyField.getText(); + } + + @Step + public int getPartitions() { + return Integer.parseInt(partitionsField.getText().trim()); + } + + @Step + public boolean isTopicHeaderVisible(String topicName) { + return isVisible($x(String.format(topicHeaderLocator, topicName))); + } + + @Step + public TopicDetails clickDeleteTopicMenu() { + removeTopicBtn.shouldBe(Condition.visible).click(); + return this; + } + + @Step + public TopicDetails clickConfirmBtnMdl() { + clickConfirmButton(); + return this; + } + + @Step + public TopicDetails clickProduceMessageBtn() { + clickByJavaScript(produceMessageBtn); + return this; + } + + @Step + public TopicDetails selectSeekTypeDdlMessagesTab(String seekTypeName) { + seekTypeDdl.shouldBe(Condition.enabled).click(); + $x(String.format(seekFilterDdlLocator, seekTypeName)).shouldBe(Condition.visible).click(); + return this; + } + + @Step + public TopicDetails setSeekTypeValueFldMessagesTab(String seekTypeValue) { + seekTypeField.shouldBe(Condition.enabled).sendKeys(seekTypeValue); + return this; + } + + @Step + public TopicDetails clickSubmitFiltersBtnMessagesTab() { + clickByJavaScript(submitBtn); + waitUntilSpinnerDisappear(); + return this; + } + + @Step + public TopicDetails clickMessagesAddFiltersBtn() { + addFiltersBtn.shouldBe(Condition.enabled).click(); + return this; + } + + @Step + public TopicDetails clickNextButton() { + nextBtn.shouldBe(Condition.enabled).click(); + waitUntilSpinnerDisappear(); + return this; + } + + @Step + public TopicDetails openSavedFiltersListMdl() { + savedFiltersLink.shouldBe(Condition.enabled).click(); + backToCreateFiltersLink.shouldBe(Condition.visible); + return this; + } + + @Step + public boolean isFilterVisibleAtSavedFiltersMdl(String filterName) { + return isVisible($x(String.format(savedFilterNameLocator, filterName))); + } + + @Step + public TopicDetails selectFilterAtSavedFiltersMdl(String filterName) { + $x(String.format(savedFilterNameLocator, filterName)).shouldBe(Condition.enabled).click(); + return this; + } + + @Step + public TopicDetails clickSelectFilterBtnAtSavedFiltersMdl() { + selectFilterBtnAddFilterMdl.shouldBe(Condition.enabled).click(); + addFilterCodeModalTitle.shouldBe(Condition.disappear); + return this; + } + + @Step + public TopicDetails waitUntilAddFiltersMdlVisible() { + addFilterCodeModalTitle.shouldBe(Condition.visible); + return this; + } + + @Step + public TopicDetails setFilterCodeFieldAddFilterMdl(String filterCode) { + addFilterCodeInput.shouldBe(Condition.enabled).sendKeys(filterCode); + return this; + } + + @Step + public TopicDetails selectSaveThisFilterCheckboxMdl(boolean select) { + selectElement(saveThisFilterCheckBoxAddFilterMdl, select); + return this; + } + + @Step + public boolean isSaveThisFilterCheckBoxSelected() { + return isSelected(saveThisFilterCheckBoxAddFilterMdl); + } + + @Step + public TopicDetails setDisplayNameFldAddFilterMdl(String displayName) { + displayNameInputAddFilterMdl.shouldBe(Condition.enabled).sendKeys(displayName); + return this; + } + + @Step + public TopicDetails clickAddFilterBtnAndCloseMdl(boolean closeModal) { + addFilterBtnAddFilterMdl.shouldBe(Condition.enabled).click(); + if (closeModal) { + addFilterCodeModalTitle.shouldBe(Condition.hidden); + } else { + addFilterCodeModalTitle.shouldBe(Condition.visible); + } + return this; + } + + @Step + public boolean isAddFilterBtnAddFilterMdlEnabled() { + return isEnabled(addFilterBtnAddFilterMdl); + } + + @Step + public boolean isBackButtonEnabled() { + return isEnabled(backBtn); + } + + @Step + public boolean isNextButtonEnabled() { + return isEnabled(nextBtn); + } + + @Step + public boolean isActiveFilterVisible(String activeFilterName) { + return isVisible($x(String.format(activeFilterNameLocator, activeFilterName))); + } + + public List getAllAddFilterModalVisibleElements() { + return Arrays.asList(savedFiltersLink, displayNameInputAddFilterMdl, addFilterBtnAddFilterMdl, + cancelBtnAddFilterMdl); + } + + public List getAllAddFilterModalEnabledElements() { + return Arrays.asList(displayNameInputAddFilterMdl, cancelBtnAddFilterMdl); + } + + public List getAllAddFilterModalDisabledElements() { + return Collections.singletonList(addFilterBtnAddFilterMdl); + } + + @Step + public TopicDetails openConsumerGroup(String consumerId) { + $x(String.format(consumerIdLocator, consumerId)).click(); + return this; + } + + private void selectYear(int expectedYear) { + while (getActualCalendarDate().getYear() > expectedYear) { + clickByJavaScript(previousMonthButton); + sleep(1000); + if (LocalTime.now().plusMinutes(3).isBefore(LocalTime.now())) { + throw new IllegalArgumentException("Unable to select year"); + } + } + } + + private void selectMonth(int expectedMonth) { + while (getActualCalendarDate().getMonthValue() > expectedMonth) { + clickByJavaScript(previousMonthButton); + sleep(1000); + if (LocalTime.now().plusMinutes(3).isBefore(LocalTime.now())) { + throw new IllegalArgumentException("Unable to select month"); + } + } + } + + private void selectDay(int expectedDay) { + Objects.requireNonNull($$x(String.format(dayCellLtr, expectedDay)).stream() + .filter(day -> !Objects.requireNonNull(day.getAttribute("class")).contains("outside-month")) + .findFirst().orElseThrow()).shouldBe(Condition.enabled).click(); + } + + private void setTime(LocalDateTime dateTime) { + calendarTimeFld.shouldBe(Condition.enabled) + .sendKeys(String.valueOf(dateTime.getHour()), String.valueOf(dateTime.getMinute())); + } + + @Step + public TopicDetails selectDateAndTimeByCalendar(LocalDateTime dateTime) { + setTime(dateTime); + selectYear(dateTime.getYear()); + selectMonth(dateTime.getMonthValue()); + selectDay(dateTime.getDayOfMonth()); + return this; + } + + private LocalDate getActualCalendarDate() { + String monthAndYearStr = actualCalendarDate.getText().trim(); + DateTimeFormatter formatter = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .append(DateTimeFormatter.ofPattern("MMMM yyyy")) + .toFormatter(Locale.ENGLISH); + YearMonth yearMonth = formatter.parse(monthAndYearStr, YearMonth::from); + return yearMonth.atDay(1); + } + + @Step + public TopicDetails openCalendarSeekType() { + seekTypeField.shouldBe(Condition.enabled).click(); + actualCalendarDate.shouldBe(Condition.visible); + return this; + } + + @Step + public int getMessageCountAmount() { + return Integer.parseInt(messageAmountCell.getText().trim()); + } + + private List initItems() { + List gridItemList = new ArrayList<>(); + gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) + .forEach(item -> gridItemList.add(new TopicDetails.MessageGridItem(item))); + return gridItemList; + } + + @Step + public TopicDetails.MessageGridItem getMessageByOffset(int offset) { + return initItems().stream() + .filter(e -> e.getOffset() == offset) + .findFirst().orElseThrow(); + } + + @Step + public TopicDetails.MessageGridItem getMessageByKey(String key) { + return initItems().stream() + .filter(e -> e.getKey().equals(key)) + .findFirst().orElseThrow(); + } + + @Step + public List getAllMessages() { + return initItems(); + } + + @Step + public TopicDetails.MessageGridItem getRandomMessage() { + return getMessageByOffset(nextInt(0, initItems().size() - 1)); + } + + public enum TopicMenu { + OVERVIEW("Overview"), + MESSAGES("Messages"), + CONSUMERS("Consumers"), + SETTINGS("Settings"); + + private final String value; + + TopicMenu(String value) { + this.value = value; + } + + public String toString() { + return value; + } + } + + public static class MessageGridItem extends BasePage { + + private final SelenideElement element; + + private MessageGridItem(SelenideElement element) { + this.element = element; } @Step - public TopicDetails openDetailsTab(TopicMenu menu) { - $(By.linkText(menu.toString())).shouldBe(Condition.visible).click(); - waitUntilSpinnerDisappear(); - return this; + public MessageGridItem clickExpand() { + clickByJavaScript(element.$x("./td[1]/span")); + return this; + } + + private SelenideElement getOffsetElm() { + return element.$x("./td[2]"); } @Step - public String getSettingsGridValueByKey(String key) { - return $x(String.format(settingsGridValueLocator, key)).scrollTo().shouldBe(Condition.visible).getText(); + public int getOffset() { + return Integer.parseInt(getOffsetElm().getText().trim()); } @Step - public TopicDetails openDotMenu() { - clickByJavaScript(dotMenuBtn); - return this; + public int getPartition() { + return Integer.parseInt(element.$x("./td[3]").getText().trim()); } @Step - public boolean isAlertWithMessageVisible(AlertHeader header, String message) { - return isAlertVisible(header, message); + public LocalDateTime getTimestamp() { + String timestampValue = element.$x("./td[4]/div").getText().trim(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy, HH:mm:ss"); + return LocalDateTime.parse(timestampValue, formatter); } @Step - public TopicDetails clickEditSettingsMenu() { - editSettingsMenu.shouldBe(Condition.visible).click(); - return this; + public String getKey() { + return element.$x("./td[5]").getText().trim(); } @Step - public boolean isConfirmationMdlVisible() { - return isConfirmationModalVisible(); + public String getValue() { + return element.$x("./td[6]").getAttribute("title"); } @Step - public TopicDetails clickClearMessagesMenu() { - clearMessagesBtn.shouldBe(Condition.visible).click(); - return this; - } - - @Step - public TopicDetails clickRecreateTopicMenu() { - recreateTopicBtn.shouldBe(Condition.visible).click(); - return this; - } - - @Step - public String getCleanUpPolicy() { - return cleanUpPolicyField.getText(); - } - - @Step - public int getPartitions() { - return Integer.parseInt(partitionsField.getText().trim()); - } - - @Step - public boolean isTopicHeaderVisible(String topicName) { - return isVisible($x(String.format(topicHeaderLocator, topicName))); - } - - @Step - public TopicDetails clickDeleteTopicMenu() { - removeTopicBtn.shouldBe(Condition.visible).click(); - return this; - } - - @Step - public TopicDetails clickConfirmBtnMdl() { - clickConfirmButton(); - return this; - } - - @Step - public TopicDetails clickProduceMessageBtn() { - clickByJavaScript(produceMessageBtn); - return this; - } - - @Step - public TopicDetails selectSeekTypeDdlMessagesTab(String seekTypeName) { - seekTypeDdl.shouldBe(Condition.enabled).click(); - $x(String.format(seekFilterDdlLocator, seekTypeName)).shouldBe(Condition.visible).click(); - return this; - } - - @Step - public TopicDetails setSeekTypeValueFldMessagesTab(String seekTypeValue) { - seekTypeField.shouldBe(Condition.enabled).sendKeys(seekTypeValue); - return this; - } - - @Step - public TopicDetails clickSubmitFiltersBtnMessagesTab() { - clickByJavaScript(submitBtn); - waitUntilSpinnerDisappear(); - return this; - } - - @Step - public TopicDetails clickMessagesAddFiltersBtn() { - addFiltersBtn.shouldBe(Condition.enabled).click(); - return this; - } - - @Step - public TopicDetails clickNextButton() { - nextBtn.shouldBe(Condition.enabled).click(); - waitUntilSpinnerDisappear(); + public MessageGridItem openDotMenu() { + getOffsetElm().hover(); + element.$x("./td[7]/div/button[@aria-label='Dropdown Toggle']") + .shouldBe(Condition.visible).click(); return this; } @Step - public TopicDetails openSavedFiltersListMdl() { - savedFiltersLink.shouldBe(Condition.enabled).click(); - backToCreateFiltersLink.shouldBe(Condition.visible); - return this; + public MessageGridItem clickCopyToClipBoard() { + clickByJavaScript(element.$x("./td[7]//li[text() = 'Copy to clipboard']") + .shouldBe(Condition.visible)); + return this; } @Step - public boolean isFilterVisibleAtSavedFiltersMdl(String filterName) { - return isVisible($x(String.format(savedFilterNameLocator, filterName))); - } - - @Step - public TopicDetails selectFilterAtSavedFiltersMdl(String filterName) { - $x(String.format(savedFilterNameLocator, filterName)).shouldBe(Condition.enabled).click(); - return this; - } - - @Step - public TopicDetails clickSelectFilterBtnAtSavedFiltersMdl() { - selectFilterBtnAddFilterMdl.shouldBe(Condition.enabled).click(); - addFilterCodeModalTitle.shouldBe(Condition.disappear); - return this; - } - - @Step - public TopicDetails waitUntilAddFiltersMdlVisible() { - addFilterCodeModalTitle.shouldBe(Condition.visible); - return this; - } - - @Step - public TopicDetails setFilterCodeFieldAddFilterMdl(String filterCode) { - addFilterCodeInput.shouldBe(Condition.enabled).sendKeys(filterCode); - return this; - } - - @Step - public TopicDetails selectSaveThisFilterCheckboxMdl(boolean select) { - selectElement(saveThisFilterCheckBoxAddFilterMdl, select); - return this; - } - - @Step - public boolean isSaveThisFilterCheckBoxSelected() { - return isSelected(saveThisFilterCheckBoxAddFilterMdl); - } - - @Step - public TopicDetails setDisplayNameFldAddFilterMdl(String displayName) { - displayNameInputAddFilterMdl.shouldBe(Condition.enabled).sendKeys(displayName); - return this; - } - - @Step - public TopicDetails clickAddFilterBtnAndCloseMdl(boolean closeModal) { - addFilterBtnAddFilterMdl.shouldBe(Condition.enabled).click(); - if (closeModal) { - addFilterCodeModalTitle.shouldBe(Condition.hidden); - } else { - addFilterCodeModalTitle.shouldBe(Condition.visible); - } - return this; - } - - @Step - public boolean isAddFilterBtnAddFilterMdlEnabled() { - return isEnabled(addFilterBtnAddFilterMdl); - } - - @Step - public boolean isBackButtonEnabled() { - return isEnabled(backBtn); - } - - @Step - public boolean isNextButtonEnabled() { - return isEnabled(nextBtn); - } - - @Step - public boolean isActiveFilterVisible(String activeFilterName) { - return isVisible($x(String.format(activeFilterNameLocator, activeFilterName))); - } - - public List getAllAddFilterModalVisibleElements() { - return Arrays.asList(savedFiltersLink, displayNameInputAddFilterMdl, addFilterBtnAddFilterMdl, cancelBtnAddFilterMdl); - } - - public List getAllAddFilterModalEnabledElements() { - return Arrays.asList(displayNameInputAddFilterMdl, cancelBtnAddFilterMdl); - } - - public List getAllAddFilterModalDisabledElements() { - return Collections.singletonList(addFilterBtnAddFilterMdl); - } - - @Step - public TopicDetails openConsumerGroup(String consumerId) { - $x(String.format(consumerIdLocator, consumerId)).click(); - return this; - } - - @Step - public boolean isKeyMessageVisible(String keyMessage) { - return keyMessage.equals($("td[title]").getText()); - } - - @Step - public boolean isContentMessageVisible(String contentMessage) { - return contentMessage.matches(contentMessageTab.getText().trim()); - } - - private void selectYear(int expectedYear) { - while (getActualCalendarDate().getYear() > expectedYear) { - clickByJavaScript(previousMonthButton); - sleep(1000); - if (LocalTime.now().plusMinutes(3).isBefore(LocalTime.now())) { - throw new IllegalArgumentException("Unable to select year"); - } - } - } - - private void selectMonth(int expectedMonth) { - while (getActualCalendarDate().getMonthValue() > expectedMonth) { - clickByJavaScript(previousMonthButton); - sleep(1000); - if (LocalTime.now().plusMinutes(3).isBefore(LocalTime.now())) { - throw new IllegalArgumentException("Unable to select month"); - } - } - } - - private void selectDay(int expectedDay) { - Objects.requireNonNull($$x(String.format(dayCellLtr, expectedDay)).stream() - .filter(day -> !Objects.requireNonNull(day.getAttribute("class")).contains("outside-month")) - .findFirst().orElseThrow()).shouldBe(Condition.enabled).click(); - } - - private void setTime(LocalDateTime dateTime) { - calendarTimeFld.shouldBe(Condition.enabled) - .sendKeys(String.valueOf(dateTime.getHour()), String.valueOf(dateTime.getMinute())); - } - - @Step - public TopicDetails selectDateAndTimeByCalendar(LocalDateTime dateTime) { - setTime(dateTime); - selectYear(dateTime.getYear()); - selectMonth(dateTime.getMonthValue()); - selectDay(dateTime.getDayOfMonth()); - return this; - } - - private LocalDate getActualCalendarDate() { - String monthAndYearStr = actualCalendarDate.getText().trim(); - DateTimeFormatter formatter = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .append(DateTimeFormatter.ofPattern("MMMM yyyy")) - .toFormatter(Locale.ENGLISH); - YearMonth yearMonth = formatter.parse(monthAndYearStr, YearMonth::from); - return yearMonth.atDay(1); - } - - @Step - public TopicDetails openCalendarSeekType() { - seekTypeField.shouldBe(Condition.enabled).click(); - actualCalendarDate.shouldBe(Condition.visible); - return this; - } - - @Step - public int getMessageCountAmount() { - return Integer.parseInt(messageAmountCell.getText().trim()); - } - - private List initItems() { - List gridItemList = new ArrayList<>(); - gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) - .forEach(item -> gridItemList.add(new TopicDetails.MessageGridItem(item))); - return gridItemList; - } - - @Step - public TopicDetails.MessageGridItem getMessageByOffset(int offset) { - return initItems().stream() - .filter(e -> e.getOffset() == offset) - .findFirst().orElseThrow(); - } - - @Step - public List getAllMessages() { - return initItems(); - } - - @Step - public TopicDetails.MessageGridItem getRandomMessage() { - return getMessageByOffset(nextInt(0, initItems().size() - 1)); - } - - public enum TopicMenu { - OVERVIEW("Overview"), - MESSAGES("Messages"), - CONSUMERS("Consumers"), - SETTINGS("Settings"); - - private final String value; - - TopicMenu(String value) { - this.value = value; - } - - public String toString() { - return value; - } - } - - public static class MessageGridItem extends BasePage { - - private final SelenideElement element; - - private MessageGridItem(SelenideElement element) { - this.element = element; - } - - @Step - public MessageGridItem clickExpand() { - clickByJavaScript(element.$x("./td[1]/span")); - return this; - } - - private SelenideElement getOffsetElm() { - return element.$x("./td[2]"); - } - - @Step - public int getOffset() { - return Integer.parseInt(getOffsetElm().getText().trim()); - } - - @Step - public int getPartition() { - return Integer.parseInt(element.$x("./td[3]").getText().trim()); - } - - @Step - public LocalDateTime getTimestamp() { - String timestampValue = element.$x("./td[4]/div").getText().trim(); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy, HH:mm:ss"); - return LocalDateTime.parse(timestampValue, formatter); - } - - @Step - public String getKey() { - return element.$x("./td[5]").getText().trim(); - } - - @Step - public String getValue() { - return element.$x("./td[6]/span/p").getText().trim(); - } - - @Step - public MessageGridItem openDotMenu() { - getOffsetElm().hover(); - element.$x("./td[7]/div/button[@aria-label='Dropdown Toggle']") - .shouldBe(Condition.visible).click(); - return this; - } - - @Step - public MessageGridItem clickCopyToClipBoard() { - clickByJavaScript(element.$x("./td[7]//li[text() = 'Copy to clipboard']") - .shouldBe(Condition.visible)); - return this; - } - - @Step - public MessageGridItem clickSaveAsFile() { - clickByJavaScript(element.$x("./td[7]//li[text() = 'Save as a file']") - .shouldBe(Condition.visible)); - return this; - } + public MessageGridItem clickSaveAsFile() { + clickByJavaScript(element.$x("./td[7]//li[text() = 'Save as a file']") + .shouldBe(Condition.visible)); + return this; } + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicSettingsTab.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicSettingsTab.java index 3c0fcac211..c36e842376 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicSettingsTab.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicSettingsTab.java @@ -1,66 +1,65 @@ package com.provectus.kafka.ui.pages.topics; +import static com.codeborne.selenide.Selenide.$x; + import com.codeborne.selenide.CollectionCondition; import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; - import java.util.ArrayList; import java.util.List; -import static com.codeborne.selenide.Selenide.$x; - public class TopicSettingsTab extends BasePage { - protected SelenideElement defaultValueColumnHeaderLocator = $x("//div[text() = 'Default Value']"); + protected SelenideElement defaultValueColumnHeaderLocator = $x("//div[text() = 'Default Value']"); - @Step - public TopicSettingsTab waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - defaultValueColumnHeaderLocator.shouldBe(Condition.visible); - return this; - } + @Step + public TopicSettingsTab waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + defaultValueColumnHeaderLocator.shouldBe(Condition.visible); + return this; + } - private List initGridItems() { - List gridItemList = new ArrayList<>(); - gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) - .forEach(item -> gridItemList.add(new SettingsGridItem(item))); - return gridItemList; - } + private List initGridItems() { + List gridItemList = new ArrayList<>(); + gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) + .forEach(item -> gridItemList.add(new SettingsGridItem(item))); + return gridItemList; + } - private TopicSettingsTab.SettingsGridItem getItemByKey(String key) { - return initGridItems().stream() - .filter(e -> e.getKey().equals(key)) - .findFirst().orElseThrow(); + private TopicSettingsTab.SettingsGridItem getItemByKey(String key) { + return initGridItems().stream() + .filter(e -> e.getKey().equals(key)) + .findFirst().orElseThrow(); + } + + @Step + public String getValueByKey(String key) { + return getItemByKey(key).getValue(); + } + + public static class SettingsGridItem extends BasePage { + + private final SelenideElement element; + + public SettingsGridItem(SelenideElement element) { + this.element = element; } @Step - public String getValueByKey(String key) { - return getItemByKey(key).getValue(); + public String getKey() { + return element.$x("./td[1]/span").getText().trim(); } - public static class SettingsGridItem extends BasePage { - - private final SelenideElement element; - - public SettingsGridItem(SelenideElement element) { - this.element = element; - } - - @Step - public String getKey() { - return element.$x("./td[1]/span").getText().trim(); - } - - @Step - public String getValue() { - return element.$x("./td[2]/span").getText().trim(); - } - - @Step - public String getDefaultValue() { - return element.$x("./td[3]/span").getText().trim(); - } + @Step + public String getValue() { + return element.$x("./td[2]/span").getText().trim(); } + + @Step + public String getDefaultValue() { + return element.$x("./td[3]/span").getText().trim(); + } + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicsList.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicsList.java index 0f25489128..184178423d 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicsList.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicsList.java @@ -1,265 +1,283 @@ package com.provectus.kafka.ui.pages.topics; +import static com.codeborne.selenide.Condition.visible; +import static com.codeborne.selenide.Selenide.$x; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.TOPICS; + import com.codeborne.selenide.CollectionCondition; import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.provectus.kafka.ui.pages.BasePage; import io.qameta.allure.Step; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.codeborne.selenide.Condition.visible; -import static com.codeborne.selenide.Selenide.$x; -import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.TOPICS; - public class TopicsList extends BasePage { - protected SelenideElement addTopicBtn = $x("//button[normalize-space(text()) ='Add a Topic']"); - protected SelenideElement searchField = $x("//input[@placeholder='Search by Topic Name']"); - protected SelenideElement showInternalRadioBtn = $x("//input[@name='ShowInternalTopics']"); - protected SelenideElement deleteSelectedTopicsBtn = $x("//button[text()='Delete selected topics']"); - protected SelenideElement copySelectedTopicBtn = $x("//button[text()='Copy selected topic']"); - protected SelenideElement purgeMessagesOfSelectedTopicsBtn = $x("//button[text()='Purge messages of selected topics']"); - protected SelenideElement clearMessagesBtn = $x("//ul[contains(@class ,'open')]//div[text()='Clear Messages']"); - protected SelenideElement recreateTopicBtn = $x("//ul[contains(@class ,'open')]//div[text()='Recreate Topic']"); - protected SelenideElement removeTopicBtn = $x("//ul[contains(@class ,'open')]//div[text()='Remove Topic']"); + protected SelenideElement addTopicBtn = $x("//button[normalize-space(text()) ='Add a Topic']"); + protected SelenideElement searchField = $x("//input[@placeholder='Search by Topic Name']"); + protected SelenideElement showInternalRadioBtn = $x("//input[@name='ShowInternalTopics']"); + protected SelenideElement deleteSelectedTopicsBtn = $x("//button[text()='Delete selected topics']"); + protected SelenideElement copySelectedTopicBtn = $x("//button[text()='Copy selected topic']"); + protected SelenideElement purgeMessagesOfSelectedTopicsBtn = + $x("//button[text()='Purge messages of selected topics']"); + protected SelenideElement clearMessagesBtn = $x("//ul[contains(@class ,'open')]//div[text()='Clear Messages']"); + protected SelenideElement recreateTopicBtn = $x("//ul[contains(@class ,'open')]//div[text()='Recreate Topic']"); + protected SelenideElement removeTopicBtn = $x("//ul[contains(@class ,'open')]//div[text()='Remove Topic']"); - @Step - public TopicsList waitUntilScreenReady() { - waitUntilSpinnerDisappear(); - getPageTitleFromHeader(TOPICS).shouldBe(visible); - return this; + @Step + public TopicsList waitUntilScreenReady() { + waitUntilSpinnerDisappear(); + getPageTitleFromHeader(TOPICS).shouldBe(visible); + return this; + } + + @Step + public TopicsList clickAddTopicBtn() { + clickByJavaScript(addTopicBtn); + return this; + } + + @Step + public boolean isTopicVisible(String topicName) { + tableGrid.shouldBe(visible); + return isVisible(getTableElement(topicName)); + } + + @Step + public boolean isShowInternalRadioBtnSelected() { + return isSelected(showInternalRadioBtn); + } + + @Step + public TopicsList setShowInternalRadioButton(boolean select) { + if (select) { + if (!showInternalRadioBtn.isSelected()) { + clickByJavaScript(showInternalRadioBtn); + waitUntilSpinnerDisappear(1); + } + } else { + if (showInternalRadioBtn.isSelected()) { + clickByJavaScript(showInternalRadioBtn); + waitUntilSpinnerDisappear(1); + } + } + return this; + } + + @Step + public TopicsList openTopic(String topicName) { + getTopicItem(topicName).openItem(); + return this; + } + + @Step + public TopicsList openDotMenuByTopicName(String topicName) { + getTopicItem(topicName).openDotMenu(); + return this; + } + + @Step + public boolean isCopySelectedTopicBtnEnabled() { + return isEnabled(copySelectedTopicBtn); + } + + @Step + public List getActionButtons() { + return Stream.of(deleteSelectedTopicsBtn, copySelectedTopicBtn, purgeMessagesOfSelectedTopicsBtn) + .collect(Collectors.toList()); + } + + @Step + public TopicsList clickCopySelectedTopicBtn() { + copySelectedTopicBtn.shouldBe(Condition.enabled).click(); + return this; + } + + @Step + public TopicsList clickPurgeMessagesOfSelectedTopicsBtn() { + purgeMessagesOfSelectedTopicsBtn.shouldBe(Condition.enabled).click(); + return this; + } + + @Step + public TopicsList clickClearMessagesBtn() { + clickByJavaScript(clearMessagesBtn.shouldBe(visible)); + return this; + } + + @Step + public TopicsList clickRecreateTopicBtn() { + clickByJavaScript(recreateTopicBtn.shouldBe(visible)); + return this; + } + + @Step + public TopicsList clickRemoveTopicBtn() { + clickByJavaScript(removeTopicBtn.shouldBe(visible)); + return this; + } + + @Step + public TopicsList clickConfirmBtnMdl() { + clickConfirmButton(); + return this; + } + + @Step + public TopicsList clickCancelBtnMdl() { + clickCancelButton(); + return this; + } + + @Step + public boolean isConfirmationMdlVisible() { + return isConfirmationModalVisible(); + } + + @Step + public boolean isAlertWithMessageVisible(AlertHeader header, String message) { + return isAlertVisible(header, message); + } + + private List getVisibleColumnHeaders() { + return Stream.of("Replication Factor", "Number of messages", "Topic Name", "Partitions", "Out of sync replicas", + "Size") + .map(name -> $x(String.format(columnHeaderLocator, name))) + .collect(Collectors.toList()); + } + + private List getEnabledColumnHeaders() { + return Stream.of("Topic Name", "Partitions", "Out of sync replicas", "Size") + .map(name -> $x(String.format(columnHeaderLocator, name))) + .collect(Collectors.toList()); + } + + @Step + public List getAllVisibleElements() { + List visibleElements = new ArrayList<>(getVisibleColumnHeaders()); + visibleElements.addAll(Arrays.asList(searchField, addTopicBtn, tableGrid)); + visibleElements.addAll(getActionButtons()); + return visibleElements; + } + + @Step + public List getAllEnabledElements() { + List enabledElements = new ArrayList<>(getEnabledColumnHeaders()); + enabledElements.addAll(Arrays.asList(searchField, showInternalRadioBtn, addTopicBtn)); + return enabledElements; + } + + private List initGridItems() { + List gridItemList = new ArrayList<>(); + gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) + .forEach(item -> gridItemList.add(new TopicGridItem(item))); + return gridItemList; + } + + @Step + public TopicGridItem getTopicItem(String name) { + TopicGridItem topicGridItem = initGridItems().stream() + .filter(e -> e.getName().equals(name)) + .findFirst().orElse(null); + if (topicGridItem == null) { + searchItem(name); + topicGridItem = initGridItems().stream() + .filter(e -> e.getName().equals(name)) + .findFirst().orElseThrow(); + } + return topicGridItem; + } + + @Step + public TopicGridItem getAnyNonInternalTopic() { + return getNonInternalTopics().stream() + .findAny().orElseThrow(); + } + + @Step + public List getNonInternalTopics() { + return initGridItems().stream() + .filter(e -> !e.isInternal()) + .collect(Collectors.toList()); + } + + @Step + public List getInternalTopics() { + return initGridItems().stream() + .filter(TopicGridItem::isInternal) + .collect(Collectors.toList()); + } + + public static class TopicGridItem extends BasePage { + + private final SelenideElement element; + + public TopicGridItem(SelenideElement element) { + this.element = element; } @Step - public TopicsList clickAddTopicBtn() { - clickByJavaScript(addTopicBtn); - return this; + public TopicsList selectItem(boolean select) { + selectElement(element.$x("./td[1]/input"), select); + return new TopicsList(); + } + + private SelenideElement getNameElm() { + return element.$x("./td[2]"); } @Step - public boolean isTopicVisible(String topicName) { - tableGrid.shouldBe(visible); - return isVisible(getTableElement(topicName)); + public boolean isInternal() { + boolean internal = false; + try { + internal = getNameElm().$x("./a/span").isDisplayed(); + } catch (Throwable ignored) { + } + return internal; } @Step - public boolean isShowInternalRadioBtnSelected() { - return isSelected(showInternalRadioBtn); + public String getName() { + return getNameElm().$x("./a").getAttribute("title"); } @Step - public TopicsList setShowInternalRadioButton(boolean select) { - selectElement(showInternalRadioBtn, select); - return this; + public void openItem() { + getNameElm().click(); } @Step - public TopicsList openTopic(String topicName) { - getTopicItem(topicName).openItem(); - return this; + public int getPartition() { + return Integer.parseInt(element.$x("./td[3]").getText().trim()); } @Step - public TopicsList openDotMenuByTopicName(String topicName) { - getTopicItem(topicName).openDotMenu(); - return this; + public int getOutOfSyncReplicas() { + return Integer.parseInt(element.$x("./td[4]").getText().trim()); } @Step - public boolean isCopySelectedTopicBtnEnabled() { - return isEnabled(copySelectedTopicBtn); + public int getReplicationFactor() { + return Integer.parseInt(element.$x("./td[5]").getText().trim()); } @Step - public List getActionButtons() { - return Stream.of(deleteSelectedTopicsBtn, copySelectedTopicBtn, purgeMessagesOfSelectedTopicsBtn) - .collect(Collectors.toList()); + public int getNumberOfMessages() { + return Integer.parseInt(element.$x("./td[6]").getText().trim()); } @Step - public TopicsList clickCopySelectedTopicBtn() { - copySelectedTopicBtn.shouldBe(Condition.enabled).click(); - return this; + public int getSize() { + return Integer.parseInt(element.$x("./td[7]").getText().trim()); } @Step - public TopicsList clickPurgeMessagesOfSelectedTopicsBtn() { - purgeMessagesOfSelectedTopicsBtn.shouldBe(Condition.enabled).click(); - return this; - } - - @Step - public TopicsList clickClearMessagesBtn() { - clickByJavaScript(clearMessagesBtn.shouldBe(visible)); - return this; - } - - @Step - public TopicsList clickRecreateTopicBtn() { - clickByJavaScript(recreateTopicBtn.shouldBe(visible)); - return this; - } - - @Step - public TopicsList clickRemoveTopicBtn() { - clickByJavaScript(removeTopicBtn.shouldBe(visible)); - return this; - } - - @Step - public TopicsList clickConfirmBtnMdl() { - clickConfirmButton(); - return this; - } - - @Step - public TopicsList clickCancelBtnMdl() { - clickCancelButton(); - return this; - } - - @Step - public boolean isConfirmationMdlVisible() { - return isConfirmationModalVisible(); - } - - @Step - public boolean isAlertWithMessageVisible(AlertHeader header, String message) { - return isAlertVisible(header, message); - } - - private List getVisibleColumnHeaders() { - return Stream.of("Replication Factor", "Number of messages", "Topic Name", "Partitions", "Out of sync replicas", "Size") - .map(name -> $x(String.format(columnHeaderLocator, name))) - .collect(Collectors.toList()); - } - - private List getEnabledColumnHeaders() { - return Stream.of("Topic Name", "Partitions", "Out of sync replicas", "Size") - .map(name -> $x(String.format(columnHeaderLocator, name))) - .collect(Collectors.toList()); - } - - @Step - public List getAllVisibleElements() { - List visibleElements = new ArrayList<>(getVisibleColumnHeaders()); - visibleElements.addAll(Arrays.asList(searchField, addTopicBtn, tableGrid)); - visibleElements.addAll(getActionButtons()); - return visibleElements; - } - - @Step - public List getAllEnabledElements() { - List enabledElements = new ArrayList<>(getEnabledColumnHeaders()); - enabledElements.addAll(Arrays.asList(searchField, showInternalRadioBtn, addTopicBtn)); - return enabledElements; - } - - private List initGridItems() { - List gridItemList = new ArrayList<>(); - gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0)) - .forEach(item -> gridItemList.add(new TopicGridItem(item))); - return gridItemList; - } - - @Step - public TopicGridItem getTopicItem(String name) { - return initGridItems().stream() - .filter(e -> e.getName().equals(name)) - .findFirst().orElseThrow(); - } - - @Step - public TopicGridItem getAnyNonInternalTopic() { - return getNonInternalTopics().stream() - .findAny().orElseThrow(); - } - - @Step - public List getNonInternalTopics() { - return initGridItems().stream() - .filter(e -> !e.isInternal()) - .collect(Collectors.toList()); - } - - @Step - public List getInternalTopics() { - return initGridItems().stream() - .filter(TopicGridItem::isInternal) - .collect(Collectors.toList()); - } - - public static class TopicGridItem extends BasePage { - - private final SelenideElement element; - - public TopicGridItem(SelenideElement element) { - this.element = element; - } - - @Step - public TopicsList selectItem(boolean select) { - selectElement(element.$x("./td[1]/input"), select); - return new TopicsList(); - } - - private SelenideElement getNameElm() { - return element.$x("./td[2]"); - } - - @Step - public boolean isInternal() { - boolean internal = false; - try { - internal = getNameElm().$x("./a/span").isDisplayed(); - } catch (Throwable ignored) { - } - return internal; - } - - @Step - public String getName() { - return getNameElm().$x("./a").getAttribute("title"); - } - - @Step - public void openItem() { - getNameElm().click(); - } - - @Step - public int getPartition() { - return Integer.parseInt(element.$x("./td[3]").getText().trim()); - } - - @Step - public int getOutOfSyncReplicas() { - return Integer.parseInt(element.$x("./td[4]").getText().trim()); - } - - @Step - public int getReplicationFactor() { - return Integer.parseInt(element.$x("./td[5]").getText().trim()); - } - - @Step - public int getNumberOfMessages() { - return Integer.parseInt(element.$x("./td[6]").getText().trim()); - } - - @Step - public int getSize() { - return Integer.parseInt(element.$x("./td[7]").getText().trim()); - } - - @Step - public void openDotMenu() { - element.$x("./td[8]//button").click(); - } + public void openDotMenu() { + element.$x("./td[8]//button").click(); } + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/CleanupPolicyValue.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/CleanupPolicyValue.java index 48c0c0fbcb..6e4d31a3a2 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/CleanupPolicyValue.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/CleanupPolicyValue.java @@ -2,24 +2,24 @@ package com.provectus.kafka.ui.pages.topics.enums; public enum CleanupPolicyValue { - DELETE("delete", "Delete"), - COMPACT("compact", "Compact"), - COMPACT_DELETE("compact,delete", "Compact,Delete"); + DELETE("delete", "Delete"), + COMPACT("compact", "Compact"), + COMPACT_DELETE("compact,delete", "Compact,Delete"); - private final String optionValue; - private final String visibleText; + private final String optionValue; + private final String visibleText; - CleanupPolicyValue(String optionValue, String visibleText) { - this.optionValue = optionValue; - this.visibleText = visibleText; - } + CleanupPolicyValue(String optionValue, String visibleText) { + this.optionValue = optionValue; + this.visibleText = visibleText; + } - public String getOptionValue() { - return optionValue; - } + public String getOptionValue() { + return optionValue; + } - public String getVisibleText() { - return visibleText; - } + public String getVisibleText() { + return visibleText; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/CustomParameterType.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/CustomParameterType.java index f4cb5cb951..4ed3e89966 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/CustomParameterType.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/CustomParameterType.java @@ -2,36 +2,36 @@ package com.provectus.kafka.ui.pages.topics.enums; public enum CustomParameterType { - COMPRESSION_TYPE("compression.type"), - DELETE_RETENTION_MS("delete.retention.ms"), - FILE_DELETE_DELAY_MS("file.delete.delay.ms"), - FLUSH_MESSAGES("flush.messages"), - FLUSH_MS("flush.ms"), - FOLLOWER_REPLICATION_THROTTLED_REPLICAS("follower.replication.throttled.replicas"), - INDEX_INTERVAL_BYTES("index.interval.bytes"), - LEADER_REPLICATION_THROTTLED_REPLICAS("leader.replication.throttled.replicas"), - MAX_COMPACTION_LAG_MS("max.compaction.lag.ms"), - MESSAGE_DOWNCONVERSION_ENABLE("message.downconversion.enable"), - MESSAGE_FORMAT_VERSION("message.format.version"), - MESSAGE_TIMESTAMP_DIFFERENCE_MAX_MS("message.timestamp.difference.max.ms"), - MESSAGE_TIMESTAMP_TYPE("message.timestamp.type"), - MIN_CLEANABLE_DIRTY_RATIO("min.cleanable.dirty.ratio"), - MIN_COMPACTION_LAG_MS("min.compaction.lag.ms"), - PREALLOCATE("preallocate"), - RETENTION_BYTES("retention.bytes"), - SEGMENT_BYTES("segment.bytes"), - SEGMENT_INDEX_BYTES("segment.index.bytes"), - SEGMENT_JITTER_MS("segment.jitter.ms"), - SEGMENT_MS("segment.ms"), - UNCLEAN_LEADER_ELECTION_ENABLE("unclean.leader.election.enable"); + COMPRESSION_TYPE("compression.type"), + DELETE_RETENTION_MS("delete.retention.ms"), + FILE_DELETE_DELAY_MS("file.delete.delay.ms"), + FLUSH_MESSAGES("flush.messages"), + FLUSH_MS("flush.ms"), + FOLLOWER_REPLICATION_THROTTLED_REPLICAS("follower.replication.throttled.replicas"), + INDEX_INTERVAL_BYTES("index.interval.bytes"), + LEADER_REPLICATION_THROTTLED_REPLICAS("leader.replication.throttled.replicas"), + MAX_COMPACTION_LAG_MS("max.compaction.lag.ms"), + MESSAGE_DOWNCONVERSION_ENABLE("message.downconversion.enable"), + MESSAGE_FORMAT_VERSION("message.format.version"), + MESSAGE_TIMESTAMP_DIFFERENCE_MAX_MS("message.timestamp.difference.max.ms"), + MESSAGE_TIMESTAMP_TYPE("message.timestamp.type"), + MIN_CLEANABLE_DIRTY_RATIO("min.cleanable.dirty.ratio"), + MIN_COMPACTION_LAG_MS("min.compaction.lag.ms"), + PREALLOCATE("preallocate"), + RETENTION_BYTES("retention.bytes"), + SEGMENT_BYTES("segment.bytes"), + SEGMENT_INDEX_BYTES("segment.index.bytes"), + SEGMENT_JITTER_MS("segment.jitter.ms"), + SEGMENT_MS("segment.ms"), + UNCLEAN_LEADER_ELECTION_ENABLE("unclean.leader.election.enable"); - private final String optionValue; + private final String optionValue; - CustomParameterType(String optionValue) { - this.optionValue = optionValue; - } + CustomParameterType(String optionValue) { + this.optionValue = optionValue; + } - public String getOptionValue() { - return optionValue; - } + public String getOptionValue() { + return optionValue; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/MaxSizeOnDisk.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/MaxSizeOnDisk.java index 8f459eea75..c77c1a9629 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/MaxSizeOnDisk.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/MaxSizeOnDisk.java @@ -2,26 +2,26 @@ package com.provectus.kafka.ui.pages.topics.enums; public enum MaxSizeOnDisk { - NOT_SET("-1", "Not Set"), - SIZE_1_GB("1073741824", "1 GB"), - SIZE_10_GB("10737418240", "10 GB"), - SIZE_20_GB("21474836480", "20 GB"), - SIZE_50_GB("53687091200", "50 GB"); + NOT_SET("-1", "Not Set"), + SIZE_1_GB("1073741824", "1 GB"), + SIZE_10_GB("10737418240", "10 GB"), + SIZE_20_GB("21474836480", "20 GB"), + SIZE_50_GB("53687091200", "50 GB"); - private final String optionValue; - private final String visibleText; + private final String optionValue; + private final String visibleText; - MaxSizeOnDisk(String optionValue, String visibleText) { - this.optionValue = optionValue; - this.visibleText = visibleText; - } + MaxSizeOnDisk(String optionValue, String visibleText) { + this.optionValue = optionValue; + this.visibleText = visibleText; + } - public String getOptionValue() { - return optionValue; - } + public String getOptionValue() { + return optionValue; + } - public String getVisibleText() { - return visibleText; - } + public String getVisibleText() { + return visibleText; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/TimeToRetain.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/TimeToRetain.java index c07abdc175..c2768ca240 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/TimeToRetain.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/TimeToRetain.java @@ -2,25 +2,25 @@ package com.provectus.kafka.ui.pages.topics.enums; public enum TimeToRetain { - BTN_12_HOURS("12 hours", "43200000"), - BTN_1_DAY("1 day", "86400000"), - BTN_2_DAYS("2 days", "172800000"), - BTN_7_DAYS("7 days", "604800000"), - BTN_4_WEEKS("4 weeks", "2419200000"); + BTN_12_HOURS("12 hours", "43200000"), + BTN_1_DAY("1 day", "86400000"), + BTN_2_DAYS("2 days", "172800000"), + BTN_7_DAYS("7 days", "604800000"), + BTN_4_WEEKS("4 weeks", "2419200000"); - private final String button; - private final String value; + private final String button; + private final String value; - TimeToRetain(String button, String value) { - this.button = button; - this.value = value; - } + TimeToRetain(String button, String value) { + this.button = button; + this.value = value; + } - public String getButton() { - return button; - } + public String getButton() { + return button; + } - public String getValue() { - return value; - } + public String getValue() { + return value; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/services/ApiService.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/services/ApiService.java index 315cf56d18..a041defc93 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/services/ApiService.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/services/ApiService.java @@ -1,272 +1,282 @@ package com.provectus.kafka.ui.services; +import static com.codeborne.selenide.Selenide.sleep; +import static com.provectus.kafka.ui.utilities.FileUtils.fileToString; + import com.fasterxml.jackson.databind.ObjectMapper; import com.provectus.kafka.ui.api.ApiClient; -import com.provectus.kafka.ui.api.api.*; -import com.provectus.kafka.ui.api.model.*; +import com.provectus.kafka.ui.api.api.KafkaConnectApi; +import com.provectus.kafka.ui.api.api.KsqlApi; +import com.provectus.kafka.ui.api.api.MessagesApi; +import com.provectus.kafka.ui.api.api.SchemasApi; +import com.provectus.kafka.ui.api.api.TopicsApi; +import com.provectus.kafka.ui.api.model.CreateTopicMessage; +import com.provectus.kafka.ui.api.model.KsqlCommandV2; +import com.provectus.kafka.ui.api.model.KsqlCommandV2Response; +import com.provectus.kafka.ui.api.model.KsqlResponse; +import com.provectus.kafka.ui.api.model.NewConnector; +import com.provectus.kafka.ui.api.model.NewSchemaSubject; +import com.provectus.kafka.ui.api.model.TopicCreation; import com.provectus.kafka.ui.models.Connector; import com.provectus.kafka.ui.models.Schema; import com.provectus.kafka.ui.models.Topic; -import com.provectus.kafka.ui.pages.ksqlDb.models.Stream; -import com.provectus.kafka.ui.pages.ksqlDb.models.Table; +import com.provectus.kafka.ui.pages.ksqldb.models.Stream; +import com.provectus.kafka.ui.pages.ksqldb.models.Table; import com.provectus.kafka.ui.settings.BaseSource; import io.qameta.allure.Step; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.reactive.function.client.WebClientResponseException; - import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; - -import static com.codeborne.selenide.Selenide.sleep; -import static com.provectus.kafka.ui.utilities.FileUtils.fileToString; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.reactive.function.client.WebClientResponseException; @Slf4j public class ApiService extends BaseSource { - @SneakyThrows - private TopicsApi topicApi() { - return new TopicsApi(new ApiClient().setBasePath(BASE_LOCAL_URL)); - } + @SneakyThrows + private TopicsApi topicApi() { + return new TopicsApi(new ApiClient().setBasePath(BASE_API_URL)); + } - @SneakyThrows - private SchemasApi schemaApi() { - return new SchemasApi(new ApiClient().setBasePath(BASE_LOCAL_URL)); - } + @SneakyThrows + private SchemasApi schemaApi() { + return new SchemasApi(new ApiClient().setBasePath(BASE_API_URL)); + } - @SneakyThrows - private KafkaConnectApi connectorApi() { - return new KafkaConnectApi(new ApiClient().setBasePath(BASE_LOCAL_URL)); - } + @SneakyThrows + private KafkaConnectApi connectorApi() { + return new KafkaConnectApi(new ApiClient().setBasePath(BASE_API_URL)); + } - @SneakyThrows - private MessagesApi messageApi() { - return new MessagesApi(new ApiClient().setBasePath(BASE_LOCAL_URL)); - } + @SneakyThrows + private MessagesApi messageApi() { + return new MessagesApi(new ApiClient().setBasePath(BASE_API_URL)); + } - @SneakyThrows - private KsqlApi ksqlApi() { - return new KsqlApi(new ApiClient().setBasePath(BASE_LOCAL_URL)); - } + @SneakyThrows + private KsqlApi ksqlApi() { + return new KsqlApi(new ApiClient().setBasePath(BASE_API_URL)); + } - @SneakyThrows - private void createTopic(String clusterName, String topicName) { - TopicCreation topic = new TopicCreation(); - topic.setName(topicName); - topic.setPartitions(1); - topic.setReplicationFactor(1); - try { - topicApi().createTopic(clusterName, topic).block(); - sleep(2000); - } catch (WebClientResponseException ex) { - ex.printStackTrace(); - } + @SneakyThrows + private void createTopic(String clusterName, String topicName) { + TopicCreation topic = new TopicCreation(); + topic.setName(topicName); + topic.setPartitions(1); + topic.setReplicationFactor(1); + try { + topicApi().createTopic(clusterName, topic).block(); + sleep(2000); + } catch (WebClientResponseException ex) { + ex.printStackTrace(); } + } - @Step - public ApiService createTopic(Topic topic) { - createTopic(CLUSTER_NAME, topic.getName()); - return this; - } + @Step + public ApiService createTopic(Topic topic) { + createTopic(CLUSTER_NAME, topic.getName()); + return this; + } - @SneakyThrows - private void deleteTopic(String clusterName, String topicName) { - try { - topicApi().deleteTopic(clusterName, topicName).block(); - } catch (WebClientResponseException ignore) { - } + @SneakyThrows + private void deleteTopic(String clusterName, String topicName) { + try { + topicApi().deleteTopic(clusterName, topicName).block(); + } catch (WebClientResponseException ignored) { } + } - @Step - public ApiService deleteTopic(String topicName) { - deleteTopic(CLUSTER_NAME, topicName); - return this; - } + @Step + public ApiService deleteTopic(String topicName) { + deleteTopic(CLUSTER_NAME, topicName); + return this; + } - @SneakyThrows - private void createSchema(String clusterName, Schema schema) { - NewSchemaSubject schemaSubject = new NewSchemaSubject(); - schemaSubject.setSubject(schema.getName()); - schemaSubject.setSchema(fileToString(schema.getValuePath())); - schemaSubject.setSchemaType(schema.getType()); - try { - schemaApi().createNewSchema(clusterName, schemaSubject).block(); - } catch (WebClientResponseException ex) { - ex.printStackTrace(); - } + @SneakyThrows + private void createSchema(String clusterName, Schema schema) { + NewSchemaSubject schemaSubject = new NewSchemaSubject(); + schemaSubject.setSubject(schema.getName()); + schemaSubject.setSchema(fileToString(schema.getValuePath())); + schemaSubject.setSchemaType(schema.getType()); + try { + schemaApi().createNewSchema(clusterName, schemaSubject).block(); + } catch (WebClientResponseException ex) { + ex.printStackTrace(); } + } - @Step - public ApiService createSchema(Schema schema) { - createSchema(CLUSTER_NAME, schema); - return this; - } + @Step + public ApiService createSchema(Schema schema) { + createSchema(CLUSTER_NAME, schema); + return this; + } - @SneakyThrows - private void deleteSchema(String clusterName, String schemaName) { - try { - schemaApi().deleteSchema(clusterName, schemaName).block(); - } catch (WebClientResponseException ignore) { - } + @SneakyThrows + private void deleteSchema(String clusterName, String schemaName) { + try { + schemaApi().deleteSchema(clusterName, schemaName).block(); + } catch (WebClientResponseException ignored) { } + } - @Step - public ApiService deleteSchema(String schemaName) { - deleteSchema(CLUSTER_NAME, schemaName); - return this; - } + @Step + public ApiService deleteSchema(String schemaName) { + deleteSchema(CLUSTER_NAME, schemaName); + return this; + } - @SneakyThrows - private void deleteConnector(String clusterName, String connectName, String connectorName) { - try { - connectorApi().deleteConnector(clusterName, connectName, connectorName).block(); - } catch (WebClientResponseException ignore) { - } + @SneakyThrows + private void deleteConnector(String clusterName, String connectName, String connectorName) { + try { + connectorApi().deleteConnector(clusterName, connectName, connectorName).block(); + } catch (WebClientResponseException ignored) { } + } - @Step - public ApiService deleteConnector(String connectName, String connectorName) { - deleteConnector(CLUSTER_NAME, connectName, connectorName); - return this; - } + @Step + public ApiService deleteConnector(String connectName, String connectorName) { + deleteConnector(CLUSTER_NAME, connectName, connectorName); + return this; + } - @Step - public ApiService deleteConnector(String connectorName) { - deleteConnector(CLUSTER_NAME, CONNECT_NAME, connectorName); - return this; - } + @Step + public ApiService deleteConnector(String connectorName) { + deleteConnector(CLUSTER_NAME, CONNECT_NAME, connectorName); + return this; + } - @SneakyThrows - private void createConnector(String clusterName, String connectName, Connector connector) { - NewConnector connectorProperties = new NewConnector(); - connectorProperties.setName(connector.getName()); - Map configMap = new ObjectMapper().readValue(connector.getConfig(), HashMap.class); - connectorProperties.setConfig(configMap); - try { - connectorApi().deleteConnector(clusterName, connectName, connector.getName()).block(); - } catch (WebClientResponseException ignored) { - } - connectorApi().createConnector(clusterName, connectName, connectorProperties).block(); + @SneakyThrows + private void createConnector(String clusterName, String connectName, Connector connector) { + NewConnector connectorProperties = new NewConnector(); + connectorProperties.setName(connector.getName()); + Map configMap = new ObjectMapper().readValue(connector.getConfig(), HashMap.class); + connectorProperties.setConfig(configMap); + try { + connectorApi().deleteConnector(clusterName, connectName, connector.getName()).block(); + } catch (WebClientResponseException ignored) { } + connectorApi().createConnector(clusterName, connectName, connectorProperties).block(); + } - @Step - public ApiService createConnector(String connectName, Connector connector) { - createConnector(CLUSTER_NAME, connectName, connector); - return this; - } + @Step + public ApiService createConnector(String connectName, Connector connector) { + createConnector(CLUSTER_NAME, connectName, connector); + return this; + } - @Step - public ApiService createConnector(Connector connector) { - createConnector(CLUSTER_NAME, CONNECT_NAME, connector); - return this; - } + @Step + public ApiService createConnector(Connector connector) { + createConnector(CLUSTER_NAME, CONNECT_NAME, connector); + return this; + } - @Step - public String getFirstConnectName(String clusterName) { - return Objects.requireNonNull(connectorApi().getConnects(clusterName).blockFirst()).getName(); - } + @Step + public String getFirstConnectName(String clusterName) { + return Objects.requireNonNull(connectorApi().getConnects(clusterName).blockFirst()).getName(); + } - @SneakyThrows - private void sendMessage(String clusterName, Topic topic) { - CreateTopicMessage createMessage = new CreateTopicMessage(); - createMessage.setPartition(0); - createMessage.setKeySerde("String"); - createMessage.setValueSerde("String"); - createMessage.setKey(topic.getMessageKey()); - createMessage.setContent(topic.getMessageContent()); - try { - messageApi().sendTopicMessages(clusterName, topic.getName(), createMessage).block(); - } catch (WebClientResponseException ex) { - ex.getRawStatusCode(); - } + @SneakyThrows + private void sendMessage(String clusterName, Topic topic) { + CreateTopicMessage createMessage = new CreateTopicMessage(); + createMessage.setPartition(0); + createMessage.setKeySerde("String"); + createMessage.setValueSerde("String"); + createMessage.setKey(topic.getMessageKey()); + createMessage.setContent(topic.getMessageValue()); + try { + messageApi().sendTopicMessages(clusterName, topic.getName(), createMessage).block(); + } catch (WebClientResponseException ex) { + ex.getRawStatusCode(); } + } - @Step - public ApiService sendMessage(Topic topic) { - sendMessage(CLUSTER_NAME, topic); - return this; - } + @Step + public ApiService sendMessage(Topic topic) { + sendMessage(CLUSTER_NAME, topic); + return this; + } - @Step - public ApiService createStream(Stream stream) { - KsqlCommandV2Response pipeIdStream = ksqlApi() - .executeKsql(CLUSTER_NAME, new KsqlCommandV2() - .ksql(String.format("CREATE STREAM %s (profileId VARCHAR, latitude DOUBLE, longitude DOUBLE) ", - stream.getName()) - + String.format("WITH (kafka_topic='%s', value_format='json', partitions=1);", - stream.getTopicName()))) - .block(); - assert pipeIdStream != null; - List responseListStream = ksqlApi() - .openKsqlResponsePipe(CLUSTER_NAME, pipeIdStream.getPipeId()) - .collectList() - .block(); - assert Objects.requireNonNull(responseListStream).size() != 0; - return this; - } + @Step + public ApiService createStream(Stream stream) { + KsqlCommandV2Response pipeIdStream = ksqlApi() + .executeKsql(CLUSTER_NAME, new KsqlCommandV2() + .ksql(String.format("CREATE STREAM %s (profileId VARCHAR, latitude DOUBLE, longitude DOUBLE) ", + stream.getName()) + + String.format("WITH (kafka_topic='%s', value_format='json', partitions=1);", + stream.getTopicName()))) + .block(); + assert pipeIdStream != null; + List responseListStream = ksqlApi() + .openKsqlResponsePipe(CLUSTER_NAME, pipeIdStream.getPipeId()) + .collectList() + .block(); + assert Objects.requireNonNull(responseListStream).size() != 0; + return this; + } - @Step - public ApiService createTables(Table firstTable, Table secondTable) { - KsqlCommandV2Response pipeIdTable1 = ksqlApi() - .executeKsql(CLUSTER_NAME, new KsqlCommandV2() - .ksql(String.format("CREATE TABLE %s AS ", firstTable.getName()) - + " SELECT profileId, " - + " LATEST_BY_OFFSET(latitude) AS la, " - + " LATEST_BY_OFFSET(longitude) AS lo " - + String.format(" FROM %s ", firstTable.getStreamName()) - + " GROUP BY profileId " - + " EMIT CHANGES;")) - .block(); - assert pipeIdTable1 != null; - List responseListTable = ksqlApi() - .openKsqlResponsePipe(CLUSTER_NAME, pipeIdTable1.getPipeId()) - .collectList() - .block(); - assert Objects.requireNonNull(responseListTable).size() != 0; - KsqlCommandV2Response pipeIdTable2 = ksqlApi() - .executeKsql(CLUSTER_NAME, new KsqlCommandV2() - .ksql(String.format("CREATE TABLE %s AS ", secondTable.getName()) - + " SELECT ROUND(GEO_DISTANCE(la, lo, 37.4133, -122.1162), -1) AS distanceInMiles, " - + " COLLECT_LIST(profileId) AS riders, " - + " COUNT(*) AS count " - + String.format(" FROM %s ", firstTable.getName()) - + " GROUP BY ROUND(GEO_DISTANCE(la, lo, 37.4133, -122.1162), -1);")) - .block(); - assert pipeIdTable2 != null; - List responseListTable2 = ksqlApi() - .openKsqlResponsePipe(CLUSTER_NAME, pipeIdTable2.getPipeId()) - .collectList() - .block(); - assert Objects.requireNonNull(responseListTable2).size() != 0; - return this; - } + @Step + public ApiService createTables(Table firstTable, Table secondTable) { + KsqlCommandV2Response pipeIdTable1 = ksqlApi() + .executeKsql(CLUSTER_NAME, new KsqlCommandV2() + .ksql(String.format("CREATE TABLE %s AS ", firstTable.getName()) + + " SELECT profileId, " + + " LATEST_BY_OFFSET(latitude) AS la, " + + " LATEST_BY_OFFSET(longitude) AS lo " + + String.format(" FROM %s ", firstTable.getStreamName()) + + " GROUP BY profileId " + + " EMIT CHANGES;")) + .block(); + assert pipeIdTable1 != null; + List responseListTable = ksqlApi() + .openKsqlResponsePipe(CLUSTER_NAME, pipeIdTable1.getPipeId()) + .collectList() + .block(); + assert Objects.requireNonNull(responseListTable).size() != 0; + KsqlCommandV2Response pipeIdTable2 = ksqlApi() + .executeKsql(CLUSTER_NAME, new KsqlCommandV2() + .ksql(String.format("CREATE TABLE %s AS ", secondTable.getName()) + + " SELECT ROUND(GEO_DISTANCE(la, lo, 37.4133, -122.1162), -1) AS distanceInMiles, " + + " COLLECT_LIST(profileId) AS riders, " + + " COUNT(*) AS count " + + String.format(" FROM %s ", firstTable.getName()) + + " GROUP BY ROUND(GEO_DISTANCE(la, lo, 37.4133, -122.1162), -1);")) + .block(); + assert pipeIdTable2 != null; + List responseListTable2 = ksqlApi() + .openKsqlResponsePipe(CLUSTER_NAME, pipeIdTable2.getPipeId()) + .collectList() + .block(); + assert Objects.requireNonNull(responseListTable2).size() != 0; + return this; + } - @Step - public ApiService insertInto(Stream stream) { - String streamName = stream.getName(); - KsqlCommandV2Response pipeIdInsert = ksqlApi() - .executeKsql(CLUSTER_NAME, new KsqlCommandV2() - .ksql("INSERT INTO " + streamName + " (profileId, latitude, longitude) VALUES ('c2309eec', 37.7877, -122.4205);" - + "INSERT INTO " + streamName + - " (profileId, latitude, longitude) VALUES ('18f4ea86', 37.3903, -122.0643); " - + "INSERT INTO " + streamName + - " (profileId, latitude, longitude) VALUES ('4ab5cbad', 37.3952, -122.0813); " - + "INSERT INTO " + streamName + - " (profileId, latitude, longitude) VALUES ('8b6eae59', 37.3944, -122.0813); " - + "INSERT INTO " + streamName + - " (profileId, latitude, longitude) VALUES ('4a7c7b41', 37.4049, -122.0822); " - + "INSERT INTO " + streamName + - " (profileId, latitude, longitude) VALUES ('4ddad000', 37.7857, -122.4011);")) - .block(); - assert pipeIdInsert != null; - List responseListInsert = ksqlApi() - .openKsqlResponsePipe(CLUSTER_NAME, pipeIdInsert.getPipeId()) - .collectList() - .block(); - assert Objects.requireNonNull(responseListInsert).size() != 0; - return this; - } + @Step + public ApiService insertInto(Stream stream) { + String streamName = stream.getName(); + KsqlCommandV2Response pipeIdInsert = ksqlApi() + .executeKsql(CLUSTER_NAME, new KsqlCommandV2() + .ksql("INSERT INTO " + streamName + + " (profileId, latitude, longitude) VALUES ('c2309eec', 37.7877, -122.4205);" + + "INSERT INTO " + streamName + + " (profileId, latitude, longitude) VALUES ('18f4ea86', 37.3903, -122.0643); " + + "INSERT INTO " + streamName + + " (profileId, latitude, longitude) VALUES ('4ab5cbad', 37.3952, -122.0813); " + + "INSERT INTO " + streamName + + " (profileId, latitude, longitude) VALUES ('8b6eae59', 37.3944, -122.0813); " + + "INSERT INTO " + streamName + + " (profileId, latitude, longitude) VALUES ('4a7c7b41', 37.4049, -122.0822); " + + "INSERT INTO " + streamName + + " (profileId, latitude, longitude) VALUES ('4ddad000', 37.7857, -122.4011);")) + .block(); + assert pipeIdInsert != null; + List responseListInsert = ksqlApi() + .openKsqlResponsePipe(CLUSTER_NAME, pipeIdInsert.getPipeId()) + .collectList() + .block(); + assert Objects.requireNonNull(responseListInsert).size() != 0; + return this; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/BaseSource.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/BaseSource.java index d294c5a116..821f2ba648 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/BaseSource.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/BaseSource.java @@ -1,22 +1,29 @@ package com.provectus.kafka.ui.settings; +import static com.provectus.kafka.ui.variables.Browser.LOCAL; + import com.provectus.kafka.ui.settings.configs.Config; import org.aeonbits.owner.ConfigFactory; public abstract class BaseSource { - public static final String BASE_CONTAINER_URL = "http://host.testcontainers.internal:8080"; - public static final String BASE_LOCAL_URL = "http://localhost:8080"; - public static final String CLUSTER_NAME = "local"; - public static final String CONNECT_NAME = "first"; - private static Config config; - public static final String BROWSER = config().browser(); - public static final String SUITE_NAME = config().suite(); + public static final String CLUSTER_NAME = "local"; + public static final String CONNECT_NAME = "first"; + private static final String LOCAL_HOST = "localhost"; + public static final String REMOTE_URL = String.format("http://%s:4444/wd/hub", LOCAL_HOST); + public static final String BASE_API_URL = String.format("http://%s:8080", LOCAL_HOST); + private static Config config; + public static final String BROWSER = config().browser(); + public static final String BASE_HOST = BROWSER.equals(LOCAL) + ? LOCAL_HOST + : "host.docker.internal"; + public static final String BASE_UI_URL = String.format("http://%s:8080", BASE_HOST); + public static final String SUITE_NAME = config().suite(); - private static Config config() { - if (config == null) { - config = ConfigFactory.create(Config.class, System.getProperties()); - } - return config; + private static Config config() { + if (config == null) { + config = ConfigFactory.create(Config.class, System.getProperties()); } + return config; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/configs/Profiles.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/configs/Profiles.java index ef61d7d770..fb9f9c1b19 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/configs/Profiles.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/configs/Profiles.java @@ -1,17 +1,17 @@ package com.provectus.kafka.ui.settings.configs; -import org.aeonbits.owner.Config; - import static com.provectus.kafka.ui.variables.Browser.CONTAINER; import static com.provectus.kafka.ui.variables.Suite.CUSTOM; +import org.aeonbits.owner.Config; + public interface Profiles extends Config { - @Key("browser") - @DefaultValue(CONTAINER) - String browser(); + @Key("browser") + @DefaultValue(CONTAINER) + String browser(); - @Key("suite") - @DefaultValue(CUSTOM) - String suite(); + @Key("suite") + @DefaultValue(CUSTOM) + String suite(); } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/drivers/LocalWebDriver.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/drivers/LocalWebDriver.java deleted file mode 100644 index e96213dd06..0000000000 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/drivers/LocalWebDriver.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.provectus.kafka.ui.settings.drivers; - -import static com.codeborne.selenide.Selenide.clearBrowserCookies; -import static com.codeborne.selenide.Selenide.clearBrowserLocalStorage; -import static com.codeborne.selenide.Selenide.open; -import static com.codeborne.selenide.Selenide.refresh; - -import com.codeborne.selenide.Configuration; -import com.codeborne.selenide.WebDriverRunner; -import com.codeborne.selenide.logevents.SelenideLogger; -import io.qameta.allure.Step; -import io.qameta.allure.selenide.AllureSelenide; -import org.openqa.selenium.chrome.ChromeOptions; - -public abstract class LocalWebDriver { - - private static org.openqa.selenium.WebDriver getWebDriver() { - try { - return WebDriverRunner.getWebDriver(); - } catch (IllegalStateException ex) { - Configuration.headless = false; - Configuration.browser = "chrome"; - Configuration.browserSize = "1920x1080"; - /**screenshots and savePageSource config is needed for local debug - * optionally can be set as 'false' to not duplicate Allure report - */ - Configuration.screenshots = true; - Configuration.savePageSource = true; - Configuration.pageLoadTimeout = 120000; - Configuration.browserCapabilities = new ChromeOptions() - .addArguments("--remote-allow-origins=*") - .addArguments("--lang=en_US"); - open(); - return WebDriverRunner.getWebDriver(); - } - } - - @Step - public static void openUrl(String url) { - if (!getWebDriver().getCurrentUrl().equals(url)) { - getWebDriver().get(url); - } - } - - @Step - public static void browserInit() { - getWebDriver(); - } - - @Step - public static void browserClear() { - clearBrowserLocalStorage(); - clearBrowserCookies(); - refresh(); - } - - @Step - public static void browserQuit() { - getWebDriver().quit(); - } - - @Step - public static void loggerSetup() { - SelenideLogger.addListener("AllureSelenide", new AllureSelenide() - .screenshots(true) - .savePageSource(false)); - } -} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/drivers/WebDriver.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/drivers/WebDriver.java new file mode 100644 index 0000000000..df1c55bc2f --- /dev/null +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/drivers/WebDriver.java @@ -0,0 +1,101 @@ +package com.provectus.kafka.ui.settings.drivers; + +import static com.codeborne.selenide.Selenide.clearBrowserCookies; +import static com.codeborne.selenide.Selenide.clearBrowserLocalStorage; +import static com.codeborne.selenide.Selenide.refresh; +import static com.provectus.kafka.ui.settings.BaseSource.BROWSER; +import static com.provectus.kafka.ui.settings.BaseSource.REMOTE_URL; +import static com.provectus.kafka.ui.variables.Browser.CONTAINER; +import static com.provectus.kafka.ui.variables.Browser.LOCAL; + +import com.codeborne.selenide.Configuration; +import com.codeborne.selenide.Selenide; +import com.codeborne.selenide.WebDriverRunner; +import com.codeborne.selenide.logevents.SelenideLogger; +import io.qameta.allure.Step; +import io.qameta.allure.selenide.AllureSelenide; +import lombok.extern.slf4j.Slf4j; +import org.openqa.selenium.chrome.ChromeOptions; +import org.openqa.selenium.remote.DesiredCapabilities; + +@Slf4j +public abstract class WebDriver { + + @Step + public static void browserSetup() { + Configuration.headless = false; + Configuration.browser = "chrome"; + Configuration.browserSize = "1920x1080"; + Configuration.screenshots = true; + Configuration.savePageSource = false; + Configuration.pageLoadTimeout = 120000; + ChromeOptions options = new ChromeOptions() + .addArguments("--no-sandbox") + .addArguments("--verbose") + .addArguments("--remote-allow-origins=*") + .addArguments("--disable-dev-shm-usage") + .addArguments("--disable-gpu") + .addArguments("--lang=en_US"); + switch (BROWSER) { + case (LOCAL) -> Configuration.browserCapabilities = options; + case (CONTAINER) -> { + Configuration.remote = REMOTE_URL; + Configuration.remoteConnectionTimeout = 180000; + DesiredCapabilities capabilities = new DesiredCapabilities(); + capabilities.setCapability("enableVNC", true); + capabilities.setCapability("enableVideo", false); + Configuration.browserCapabilities = capabilities.merge(options); + } + default -> throw new IllegalStateException("Unexpected value: " + BROWSER); + } + } + + private static org.openqa.selenium.WebDriver getWebDriver() { + try { + return WebDriverRunner.getWebDriver(); + } catch (IllegalStateException ex) { + browserSetup(); + Selenide.open(); + return WebDriverRunner.getWebDriver(); + } + } + + @Step + public static void openUrl(String url) { + org.openqa.selenium.WebDriver driver = getWebDriver(); + if (!driver.getCurrentUrl().equals(url)) { + driver.get(url); + } + } + + @Step + public static void browserInit() { + getWebDriver(); + } + + @Step + public static void browserClear() { + clearBrowserLocalStorage(); + clearBrowserCookies(); + refresh(); + } + + @Step + public static void browserQuit() { + org.openqa.selenium.WebDriver driver = null; + try { + driver = WebDriverRunner.getWebDriver(); + } catch (Throwable ignored) { + } + if (driver != null) { + driver.quit(); + } + } + + @Step + public static void loggerSetup() { + SelenideLogger.addListener("AllureSelenide", new AllureSelenide() + .screenshots(true) + .savePageSource(false)); + } +} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/AllureListener.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/AllureListener.java index 74119f8480..61125408c6 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/AllureListener.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/AllureListener.java @@ -1,35 +1,39 @@ package com.provectus.kafka.ui.settings.listeners; +import static java.nio.file.Files.newInputStream; + import com.codeborne.selenide.Screenshots; import io.qameta.allure.Allure; import io.qameta.allure.testng.AllureTestNg; +import java.io.File; +import java.io.IOException; +import lombok.extern.slf4j.Slf4j; import org.testng.ITestListener; import org.testng.ITestResult; -import java.io.File; -import java.io.IOException; -import java.util.Objects; - -import static java.nio.file.Files.newInputStream; - +@Slf4j public class AllureListener extends AllureTestNg implements ITestListener { - private void takeScreenshot() { - File screenshot = Screenshots.takeScreenShotAsFile(); - try { - Allure.addAttachment(Objects.requireNonNull(screenshot).getName(), newInputStream(screenshot.toPath())); - } catch (IOException e) { - throw new RuntimeException(e); - } + private void takeScreenshot() { + File screenshot = Screenshots.takeScreenShotAsFile(); + try { + if (screenshot != null) { + Allure.addAttachment(screenshot.getName(), newInputStream(screenshot.toPath())); + } else { + log.warn("Unable to take screenshot"); + } + } catch (IOException e) { + throw new RuntimeException(e); } + } - @Override - public void onTestFailure(ITestResult result) { - takeScreenshot(); - } + @Override + public void onTestFailure(ITestResult result) { + takeScreenshot(); + } - @Override - public void onTestSkipped(ITestResult result) { - takeScreenshot(); - } + @Override + public void onTestSkipped(ITestResult result) { + takeScreenshot(); + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/LoggerListener.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/LoggerListener.java index ca096cd238..81f510f752 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/LoggerListener.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/LoggerListener.java @@ -7,31 +7,31 @@ import org.testng.TestListenerAdapter; @Slf4j public class LoggerListener extends TestListenerAdapter { - @Override - public void onTestStart(final ITestResult testResult) { - log.info(String.format("\n------------------------------------------------------------------------ " + - "\nTEST STARTED: %s.%s \n------------------------------------------------------------------------ \n", - testResult.getInstanceName(), testResult.getName())); - } + @Override + public void onTestStart(final ITestResult testResult) { + log.info(String.format("\n------------------------------------------------------------------------ " + + "\nTEST STARTED: %s.%s \n------------------------------------------------------------------------ \n", + testResult.getInstanceName(), testResult.getName())); + } - @Override - public void onTestSuccess(final ITestResult testResult) { - log.info(String.format("\n------------------------------------------------------------------------ " + - "\nTEST PASSED: %s.%s \n------------------------------------------------------------------------ \n", - testResult.getInstanceName(), testResult.getName())); - } + @Override + public void onTestSuccess(final ITestResult testResult) { + log.info(String.format("\n------------------------------------------------------------------------ " + + "\nTEST PASSED: %s.%s \n------------------------------------------------------------------------ \n", + testResult.getInstanceName(), testResult.getName())); + } - @Override - public void onTestFailure(final ITestResult testResult) { - log.info(String.format("\n------------------------------------------------------------------------ " + - "\nTEST FAILED: %s.%s \n------------------------------------------------------------------------ \n", - testResult.getInstanceName(), testResult.getName())); - } + @Override + public void onTestFailure(final ITestResult testResult) { + log.info(String.format("\n------------------------------------------------------------------------ " + + "\nTEST FAILED: %s.%s \n------------------------------------------------------------------------ \n", + testResult.getInstanceName(), testResult.getName())); + } - @Override - public void onTestSkipped(final ITestResult testResult) { - log.info(String.format("\n------------------------------------------------------------------------ " + - "\nTEST SKIPPED: %s.%s \n------------------------------------------------------------------------ \n", - testResult.getInstanceName(), testResult.getName())); - } + @Override + public void onTestSkipped(final ITestResult testResult) { + log.info(String.format("\n------------------------------------------------------------------------ " + + "\nTEST SKIPPED: %s.%s \n------------------------------------------------------------------------ \n", + testResult.getInstanceName(), testResult.getName())); + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseCreateListener.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseCreateListener.java index c40481c300..ac3f84eba4 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseCreateListener.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseCreateListener.java @@ -1,14 +1,28 @@ package com.provectus.kafka.ui.settings.listeners; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Automation; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Status; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Suite; +import static io.qase.api.utils.IntegrationUtils.getCaseTitle; + +import com.provectus.kafka.ui.utilities.qase.annotations.Automation; +import com.provectus.kafka.ui.utilities.qase.annotations.Status; +import com.provectus.kafka.ui.utilities.qase.annotations.Suite; import io.qase.api.QaseClient; import io.qase.api.StepStorage; import io.qase.api.annotation.QaseId; import io.qase.client.ApiClient; import io.qase.client.api.CasesApi; -import io.qase.client.model.*; +import io.qase.client.model.GetCasesFiltersParameter; +import io.qase.client.model.ResultCreateStepsInner; +import io.qase.client.model.TestCase; +import io.qase.client.model.TestCaseCreate; +import io.qase.client.model.TestCaseCreateStepsInner; +import io.qase.client.model.TestCaseListResponse; +import io.qase.client.model.TestCaseListResponseAllOfResult; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.testng.Assert; @@ -16,108 +30,107 @@ import org.testng.ITestListener; import org.testng.ITestResult; import org.testng.TestListenerAdapter; -import java.lang.reflect.Method; -import java.util.*; - -import static io.qase.api.utils.IntegrationUtils.getCaseTitle; - @Slf4j public class QaseCreateListener extends TestListenerAdapter implements ITestListener { - private static final CasesApi QASE_API = getQaseApi(); + private static final CasesApi QASE_API = getQaseApi(); - private static CasesApi getQaseApi() { - ApiClient apiClient = QaseClient.getApiClient(); - apiClient.setApiKey(System.getProperty("QASEIO_API_TOKEN")); - return new CasesApi(apiClient); + private static CasesApi getQaseApi() { + ApiClient apiClient = QaseClient.getApiClient(); + apiClient.setApiKey(System.getProperty("QASEIO_API_TOKEN")); + return new CasesApi(apiClient); + } + + private static int getStatus(Method method) { + if (method.isAnnotationPresent(Status.class)) { + return method.getDeclaredAnnotation(Status.class).status().getValue(); } + return 1; + } - private static int getStatus(Method method) { - if (method.isAnnotationPresent(Status.class)) - return method.getDeclaredAnnotation(Status.class).status().getValue(); - return 1; + private static int getAutomation(Method method) { + if (method.isAnnotationPresent(Automation.class)) { + return method.getDeclaredAnnotation(Automation.class).state().getValue(); } + return 0; + } - private static int getAutomation(Method method) { - if (method.isAnnotationPresent(Automation.class)) - return method.getDeclaredAnnotation(Automation.class).state().getValue(); - return 0; - } - - @SneakyThrows - private static HashMap getCaseTitlesAndIdsFromQase() { - HashMap cases = new HashMap<>(); - boolean getCases = true; - int offSet = 0; - while (getCases) { - getCases = false; - TestCaseListResponse response = QASE_API.getCases(System.getProperty("QASE_PROJECT_CODE"), - new GetCasesFiltersParameter().status(GetCasesFiltersParameter.SERIALIZED_NAME_STATUS), 100, offSet); - TestCaseListResponseAllOfResult result = response.getResult(); - Assert.assertNotNull(result); - List entities = result.getEntities(); - Assert.assertNotNull(entities); - if (entities.size() > 0) { - for (TestCase testCase : entities) { - cases.put(testCase.getId(), testCase.getTitle()); - } - offSet = offSet + 100; - getCases = true; - } + @SneakyThrows + private static HashMap getCaseTitlesAndIdsFromQase() { + HashMap cases = new HashMap<>(); + boolean getCases = true; + int offSet = 0; + while (getCases) { + getCases = false; + TestCaseListResponse response = QASE_API.getCases(System.getProperty("QASE_PROJECT_CODE"), + new GetCasesFiltersParameter().status(GetCasesFiltersParameter.SERIALIZED_NAME_STATUS), 100, offSet); + TestCaseListResponseAllOfResult result = response.getResult(); + Assert.assertNotNull(result); + List entities = result.getEntities(); + Assert.assertNotNull(entities); + if (entities.size() > 0) { + for (TestCase testCase : entities) { + cases.put(testCase.getId(), testCase.getTitle()); } - return cases; + offSet = offSet + 100; + getCases = true; + } } + return cases; + } - private static boolean isCaseWithTitleExistInQase(Method method) { - HashMap cases = getCaseTitlesAndIdsFromQase(); - String title = getCaseTitle(method); - if (cases.containsValue(title)) { - for (Map.Entry map : cases.entrySet()) { - if (map.getValue().matches(title)) { - long id = map.getKey(); - log.warn(String.format("Test case with @QaseTitle='%s' already exists with @QaseId=%d. " + - "Please verify @QaseTitle annotation", title, id)); - return true; - } - } + private static boolean isCaseWithTitleExistInQase(Method method) { + HashMap cases = getCaseTitlesAndIdsFromQase(); + String title = getCaseTitle(method); + if (cases.containsValue(title)) { + for (Map.Entry map : cases.entrySet()) { + if (map.getValue().matches(title)) { + long id = map.getKey(); + log.warn(String.format("Test case with @QaseTitle='%s' already exists with @QaseId=%d. " + + "Please verify @QaseTitle annotation", title, id)); + return true; } - return false; + } } + return false; + } - @Override - @SneakyThrows - public void onTestSuccess(final ITestResult testResult) { - Method method = testResult.getMethod() - .getConstructorOrMethod() - .getMethod(); - String title = getCaseTitle(method); - if (!method.isAnnotationPresent(QaseId.class)) { - if (title != null) { - if (!isCaseWithTitleExistInQase(method)) { - LinkedList resultSteps = StepStorage.stopSteps(); - LinkedList createSteps = new LinkedList<>(); - resultSteps.forEach(step -> { - TestCaseCreateStepsInner caseStep = new TestCaseCreateStepsInner(); - caseStep.setAction(step.getAction()); - caseStep.setExpectedResult(step.getExpectedResult()); - createSteps.add(caseStep); - }); - TestCaseCreate newCase = new TestCaseCreate(); - newCase.setTitle(title); - newCase.setStatus(getStatus(method)); - newCase.setAutomation(getAutomation(method)); - newCase.setSteps(createSteps); - if (method.isAnnotationPresent(Suite.class)) { - long suiteId = method.getDeclaredAnnotation(Suite.class).id(); - newCase.suiteId(suiteId); - } - Long id = Objects.requireNonNull(QASE_API.createCase(System.getProperty("QASE_PROJECT_CODE"), - newCase).getResult()).getId(); - log.info(String.format("New test case '%s' was created with @QaseId=%d", title, id)); - } - } else - log.warn("To create new test case in Qase.io please add @QaseTitle annotation"); - } else - log.warn("To create new test case in Qase.io please remove @QaseId annotation"); + @Override + @SneakyThrows + public void onTestSuccess(final ITestResult testResult) { + Method method = testResult.getMethod() + .getConstructorOrMethod() + .getMethod(); + String title = getCaseTitle(method); + if (!method.isAnnotationPresent(QaseId.class)) { + if (title != null) { + if (!isCaseWithTitleExistInQase(method)) { + LinkedList resultSteps = StepStorage.stopSteps(); + LinkedList createSteps = new LinkedList<>(); + resultSteps.forEach(step -> { + TestCaseCreateStepsInner caseStep = new TestCaseCreateStepsInner(); + caseStep.setAction(step.getAction()); + caseStep.setExpectedResult(step.getExpectedResult()); + createSteps.add(caseStep); + }); + TestCaseCreate newCase = new TestCaseCreate(); + newCase.setTitle(title); + newCase.setStatus(getStatus(method)); + newCase.setAutomation(getAutomation(method)); + newCase.setSteps(createSteps); + if (method.isAnnotationPresent(Suite.class)) { + long suiteId = method.getDeclaredAnnotation(Suite.class).id(); + newCase.suiteId(suiteId); + } + Long id = Objects.requireNonNull(QASE_API.createCase(System.getProperty("QASE_PROJECT_CODE"), + newCase).getResult()).getId(); + log.info(String.format("New test case '%s' was created with @QaseId=%d", title, id)); + } + } else { + log.warn("To create new test case in Qase.io please add @QaseTitle annotation"); + } + } else { + log.warn("To create new test case in Qase.io please remove @QaseId annotation"); } + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseResultListener.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseResultListener.java index 72056db922..d413ca4a28 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseResultListener.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseResultListener.java @@ -1,5 +1,12 @@ package com.provectus.kafka.ui.settings.listeners; +import static io.qase.api.utils.IntegrationUtils.getCaseId; +import static io.qase.api.utils.IntegrationUtils.getCaseTitle; +import static io.qase.api.utils.IntegrationUtils.getStacktrace; +import static io.qase.client.model.ResultCreate.StatusEnum.FAILED; +import static io.qase.client.model.ResultCreate.StatusEnum.PASSED; +import static io.qase.client.model.ResultCreate.StatusEnum.SKIPPED; + import io.qase.api.StepStorage; import io.qase.api.config.QaseConfig; import io.qase.api.services.QaseTestCaseListener; @@ -7,6 +14,9 @@ import io.qase.client.model.ResultCreate; import io.qase.client.model.ResultCreateCase; import io.qase.client.model.ResultCreateStepsInner; import io.qase.testng.guice.module.TestNgModule; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.Optional; import lombok.AccessLevel; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -15,88 +25,81 @@ import org.testng.ITestListener; import org.testng.ITestResult; import org.testng.TestListenerAdapter; -import java.lang.reflect.Method; -import java.util.LinkedList; -import java.util.Optional; - -import static io.qase.api.utils.IntegrationUtils.*; -import static io.qase.client.model.ResultCreate.StatusEnum.*; - @Slf4j public class QaseResultListener extends TestListenerAdapter implements ITestListener { - private static final String REPORTER_NAME = "TestNG"; + private static final String REPORTER_NAME = "TestNG"; - static { - System.setProperty(QaseConfig.QASE_CLIENT_REPORTER_NAME_KEY, REPORTER_NAME); - } - - @Getter(lazy = true, value = AccessLevel.PRIVATE) - private final QaseTestCaseListener qaseTestCaseListener = createQaseListener(); - - private static QaseTestCaseListener createQaseListener() { - return TestNgModule.getInjector().getInstance(QaseTestCaseListener.class); - } - - @Override - public void onTestStart(ITestResult tr) { - getQaseTestCaseListener().onTestCaseStarted(); - super.onTestStart(tr); - } - - @Override - public void onTestSuccess(ITestResult tr) { - getQaseTestCaseListener() - .onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, tr, PASSED)); - super.onTestSuccess(tr); - } - - @Override - public void onTestSkipped(ITestResult tr) { - getQaseTestCaseListener() - .onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, tr, SKIPPED)); - super.onTestSuccess(tr); - } - - @Override - public void onTestFailure(ITestResult tr) { - getQaseTestCaseListener() - .onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, tr, FAILED)); - super.onTestFailure(tr); - } - - @Override - public void onFinish(ITestContext testContext) { - getQaseTestCaseListener().onTestCasesSetFinished(); - super.onFinish(testContext); - } - - private void setupResultItem(ResultCreate resultCreate, ITestResult result, ResultCreate.StatusEnum status) { - Optional resultThrowable = Optional.ofNullable(result.getThrowable()); - String comment = resultThrowable - .flatMap(throwable -> Optional.of(throwable.toString())).orElse(null); - Boolean isDefect = resultThrowable - .flatMap(throwable -> Optional.of(throwable instanceof AssertionError)) - .orElse(false); - String stacktrace = resultThrowable - .flatMap(throwable -> Optional.of(getStacktrace(throwable))) - .orElse(null); - Method method = result.getMethod() - .getConstructorOrMethod() - .getMethod(); - Long caseId = getCaseId(method); - String caseTitle = null; - if (caseId == null) { - caseTitle = getCaseTitle(method); - } - LinkedList steps = StepStorage.stopSteps(); - resultCreate - ._case(caseTitle == null ? null : new ResultCreateCase().title(caseTitle)) - .caseId(caseId) - .status(status) - .comment(comment) - .stacktrace(stacktrace) - .steps(steps.isEmpty() ? null : steps) - .defect(isDefect); + static { + System.setProperty(QaseConfig.QASE_CLIENT_REPORTER_NAME_KEY, REPORTER_NAME); + } + + @Getter(lazy = true, value = AccessLevel.PRIVATE) + private final QaseTestCaseListener qaseTestCaseListener = createQaseListener(); + + private static QaseTestCaseListener createQaseListener() { + return TestNgModule.getInjector().getInstance(QaseTestCaseListener.class); + } + + @Override + public void onTestStart(ITestResult tr) { + getQaseTestCaseListener().onTestCaseStarted(); + super.onTestStart(tr); + } + + @Override + public void onTestSuccess(ITestResult tr) { + getQaseTestCaseListener() + .onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, tr, PASSED)); + super.onTestSuccess(tr); + } + + @Override + public void onTestSkipped(ITestResult tr) { + getQaseTestCaseListener() + .onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, tr, SKIPPED)); + super.onTestSuccess(tr); + } + + @Override + public void onTestFailure(ITestResult tr) { + getQaseTestCaseListener() + .onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, tr, FAILED)); + super.onTestFailure(tr); + } + + @Override + public void onFinish(ITestContext testContext) { + getQaseTestCaseListener().onTestCasesSetFinished(); + super.onFinish(testContext); + } + + private void setupResultItem(ResultCreate resultCreate, ITestResult result, ResultCreate.StatusEnum status) { + Optional resultThrowable = Optional.ofNullable(result.getThrowable()); + String comment = resultThrowable + .flatMap(throwable -> Optional.of(throwable.toString())).orElse(null); + Boolean isDefect = resultThrowable + .flatMap(throwable -> Optional.of(throwable instanceof AssertionError)) + .orElse(false); + String stacktrace = resultThrowable + .flatMap(throwable -> Optional.of(getStacktrace(throwable))) + .orElse(null); + Method method = result.getMethod() + .getConstructorOrMethod() + .getMethod(); + Long caseId = getCaseId(method); + String caseTitle = null; + if (caseId == null) { + caseTitle = getCaseTitle(method); } + LinkedList steps = StepStorage.stopSteps(); + resultCreate + ._case(caseTitle == null ? null : new ResultCreateCase().title(caseTitle)) + .caseId(caseId) + .status(status) + .comment(comment) + .stacktrace(stacktrace) + .steps(steps.isEmpty() ? null : steps) + .defect(isDefect); + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/FileUtils.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/FileUtils.java index c2489a86c2..8bb57809b8 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/FileUtils.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/FileUtils.java @@ -1,27 +1,26 @@ package com.provectus.kafka.ui.utilities; -import org.testcontainers.shaded.org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; - import static org.apache.kafka.common.utils.Utils.readFileAsString; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import org.testcontainers.shaded.org.apache.commons.io.IOUtils; + public class FileUtils { - public static String getResourceAsString(String resourceFileName) { - try { - return IOUtils.resourceToString("/" + resourceFileName, StandardCharsets.UTF_8); - } catch (IOException e) { - throw new RuntimeException(e); - } + public static String getResourceAsString(String resourceFileName) { + try { + return IOUtils.resourceToString("/" + resourceFileName, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException(e); } + } - public static String fileToString(String path) { - try { - return readFileAsString(path); - } catch (IOException e) { - throw new RuntimeException(e); - } + public static String fileToString(String path) { + try { + return readFileAsString(path); + } catch (IOException e) { + throw new RuntimeException(e); } + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/TimeUtils.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/TimeUtils.java index f53e8897e9..7f72f8a4d6 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/TimeUtils.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/TimeUtils.java @@ -1,17 +1,16 @@ package com.provectus.kafka.ui.utilities; -import lombok.extern.slf4j.Slf4j; +import static com.codeborne.selenide.Selenide.sleep; import java.time.LocalTime; - -import static com.codeborne.selenide.Selenide.sleep; +import lombok.extern.slf4j.Slf4j; @Slf4j public class TimeUtils { - public static void waitUntilNewMinuteStarted() { - int secondsLeft = 60 - LocalTime.now().getSecond(); - log.debug("\nwaitUntilNewMinuteStarted: {}s", secondsLeft); - sleep(secondsLeft * 1000); - } + public static void waitUntilNewMinuteStarted() { + int secondsLeft = 60 - LocalTime.now().getSecond(); + log.debug("\nwaitUntilNewMinuteStarted: {}s", secondsLeft); + sleep(secondsLeft * 1000); + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/WebUtils.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/WebUtils.java index 8358880503..fef5ef654a 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/WebUtils.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/WebUtils.java @@ -1,90 +1,110 @@ package com.provectus.kafka.ui.utilities; +import static com.codeborne.selenide.Selenide.executeJavaScript; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.codeborne.selenide.WebDriverRunner; +import java.time.Duration; import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.Keys; import org.openqa.selenium.interactions.Actions; -import static com.codeborne.selenide.Selenide.executeJavaScript; - @Slf4j public class WebUtils { - public static void clickByActions(SelenideElement element) { - log.debug("\nclickByActions: {}", element.getSearchCriteria()); - element.shouldBe(Condition.enabled); - new Actions(WebDriverRunner.getWebDriver()) - .moveToElement(element) - .click(element) - .perform(); - } + public static int getTimeout(int... timeoutInSeconds) { + return (timeoutInSeconds != null && timeoutInSeconds.length > 0) ? timeoutInSeconds[0] : 4; + } - public static void sendKeysByActions(SelenideElement element, String keys) { - log.debug("\nsendKeysByActions: {} \nsend keys '{}'", element.getSearchCriteria(), keys); - element.shouldBe(Condition.enabled); - new Actions(WebDriverRunner.getWebDriver()) - .moveToElement(element) - .sendKeys(element, keys) - .perform(); + public static void sendKeysAfterClear(SelenideElement element, String keys) { + log.debug("\nsendKeysAfterClear: {} \nsend keys '{}'", element.getSearchCriteria(), keys); + element.shouldBe(Condition.enabled).clear(); + if (keys != null) { + element.sendKeys(keys); } + } - public static void clickByJavaScript(SelenideElement element) { - log.debug("\nclickByJavaScript: {}", element.getSearchCriteria()); - element.shouldBe(Condition.enabled); - String script = "arguments[0].click();"; - executeJavaScript(script, element); - } + public static void clickByActions(SelenideElement element) { + log.debug("\nclickByActions: {}", element.getSearchCriteria()); + element.shouldBe(Condition.enabled); + new Actions(WebDriverRunner.getWebDriver()) + .moveToElement(element) + .click(element) + .perform(); + } - public static void clearByKeyboard(SelenideElement field) { - log.debug("\nclearByKeyboard: {}", field.getSearchCriteria()); - field.shouldBe(Condition.enabled).sendKeys(Keys.END); - field.sendKeys(Keys.chord(Keys.CONTROL + "a"), Keys.DELETE); - } + public static void sendKeysByActions(SelenideElement element, String keys) { + log.debug("\nsendKeysByActions: {} \nsend keys '{}'", element.getSearchCriteria(), keys); + element.shouldBe(Condition.enabled); + new Actions(WebDriverRunner.getWebDriver()) + .moveToElement(element) + .sendKeys(element, keys) + .perform(); + } - public static boolean isVisible(SelenideElement element) { - log.debug("\nisVisible: {}", element.getSearchCriteria()); - boolean isVisible = false; - try { - element.shouldBe(Condition.visible); - isVisible = true; - } catch (Throwable e) { - log.debug("{} is not visible", element.getSearchCriteria()); - } - return isVisible; - } + public static void clickByJavaScript(SelenideElement element) { + log.debug("\nclickByJavaScript: {}", element.getSearchCriteria()); + element.shouldBe(Condition.enabled); + String script = "arguments[0].click();"; + executeJavaScript(script, element); + } - public static boolean isEnabled(SelenideElement element) { - log.debug("\nisEnabled: {}", element.getSearchCriteria()); - boolean isEnabled = false; - try { - element.shouldBe(Condition.enabled); - isEnabled = true; - } catch (Throwable e) { - log.debug("{} is not enabled", element.getSearchCriteria()); - } - return isEnabled; - } + public static void clearByKeyboard(SelenideElement field) { + log.debug("\nclearByKeyboard: {}", field.getSearchCriteria()); + field.shouldBe(Condition.enabled).sendKeys(Keys.END); + field.sendKeys(Keys.chord(Keys.CONTROL + "a"), Keys.DELETE); + } - public static boolean isSelected(SelenideElement element) { - log.debug("\nisSelected: {}", element.getSearchCriteria()); - boolean isSelected = false; - try { - element.shouldBe(Condition.selected); - isSelected = true; - } catch (Throwable e) { - log.debug("{} is not selected", element.getSearchCriteria()); - } - return isSelected; + public static boolean isVisible(SelenideElement element, int... timeoutInSeconds) { + log.debug("\nisVisible: {}", element.getSearchCriteria()); + boolean isVisible = false; + try { + element.shouldBe(Condition.visible, + Duration.ofSeconds(getTimeout(timeoutInSeconds))); + isVisible = true; + } catch (Throwable e) { + log.debug("{} is not visible", element.getSearchCriteria()); } + return isVisible; + } - public static boolean selectElement(SelenideElement element, boolean select) { - if (select) { - if (!element.isSelected()) clickByJavaScript(element); - } else { - if (element.isSelected()) clickByJavaScript(element); - } - return true; + public static boolean isEnabled(SelenideElement element, int... timeoutInSeconds) { + log.debug("\nisEnabled: {}", element.getSearchCriteria()); + boolean isEnabled = false; + try { + element.shouldBe(Condition.enabled, + Duration.ofSeconds(getTimeout(timeoutInSeconds))); + isEnabled = true; + } catch (Throwable e) { + log.debug("{} is not enabled", element.getSearchCriteria()); } + return isEnabled; + } + + public static boolean isSelected(SelenideElement element, int... timeoutInSeconds) { + log.debug("\nisSelected: {}", element.getSearchCriteria()); + boolean isSelected = false; + try { + element.shouldBe(Condition.selected, + Duration.ofSeconds(getTimeout(timeoutInSeconds))); + isSelected = true; + } catch (Throwable e) { + log.debug("{} is not selected", element.getSearchCriteria()); + } + return isSelected; + } + + public static boolean selectElement(SelenideElement element, boolean select) { + if (select) { + if (!element.isSelected()) { + clickByJavaScript(element); + } + } else { + if (element.isSelected()) { + clickByJavaScript(element); + } + } + return true; + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/QaseSetup.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/QaseSetup.java new file mode 100644 index 0000000000..f0ed509aad --- /dev/null +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/QaseSetup.java @@ -0,0 +1,33 @@ +package com.provectus.kafka.ui.utilities.qase; + +import static com.provectus.kafka.ui.settings.BaseSource.SUITE_NAME; +import static com.provectus.kafka.ui.variables.Suite.MANUAL; +import static org.apache.commons.lang3.BooleanUtils.FALSE; +import static org.apache.commons.lang3.BooleanUtils.TRUE; +import static org.apache.commons.lang3.StringUtils.isEmpty; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class QaseSetup { + + public static void qaseIntegrationSetup() { + String qaseApiToken = System.getProperty("QASEIO_API_TOKEN"); + if (isEmpty(qaseApiToken)) { + log.warn("Integration with Qase is disabled due to run config or token wasn't defined."); + System.setProperty("QASE_ENABLE", FALSE); + } else { + log.warn("Integration with Qase is enabled. Find this run at https://app.qase.io/run/KAFKAUI."); + String automation = SUITE_NAME.equalsIgnoreCase(MANUAL) ? "" : "Automation "; + System.setProperty("QASE_ENABLE", TRUE); + System.setProperty("QASE_PROJECT_CODE", "KAFKAUI"); + System.setProperty("QASE_API_TOKEN", qaseApiToken); + System.setProperty("QASE_USE_BULK", TRUE); + System.setProperty("QASE_RUN_NAME", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm") + .format(OffsetDateTime.now(ZoneOffset.UTC)) + ": " + automation + SUITE_NAME.toUpperCase() + " suite"); + } + } +} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/annotations/Automation.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Automation.java similarity index 63% rename from kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/annotations/Automation.java rename to kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Automation.java index 556263c111..1b8d5b65b8 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/annotations/Automation.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Automation.java @@ -1,7 +1,6 @@ -package com.provectus.kafka.ui.utilities.qaseUtils.annotations; - -import com.provectus.kafka.ui.utilities.qaseUtils.enums.State; +package com.provectus.kafka.ui.utilities.qase.annotations; +import com.provectus.kafka.ui.utilities.qase.enums.State; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -11,5 +10,5 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) public @interface Automation { - State state(); + State state(); } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/annotations/Status.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Status.java similarity index 65% rename from kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/annotations/Status.java rename to kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Status.java index 3c31f2345c..df078d0436 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/annotations/Status.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Status.java @@ -1,4 +1,4 @@ -package com.provectus.kafka.ui.utilities.qaseUtils.annotations; +package com.provectus.kafka.ui.utilities.qase.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -9,5 +9,5 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) public @interface Status { - com.provectus.kafka.ui.utilities.qaseUtils.enums.Status status(); + com.provectus.kafka.ui.utilities.qase.enums.Status status(); } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/annotations/Suite.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Suite.java similarity index 76% rename from kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/annotations/Suite.java rename to kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Suite.java index fa1c2c3dd7..fcaff09744 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/annotations/Suite.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Suite.java @@ -1,4 +1,4 @@ -package com.provectus.kafka.ui.utilities.qaseUtils.annotations; +package com.provectus.kafka.ui.utilities.qase.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -9,5 +9,5 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) public @interface Suite { - long id(); + long id(); } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/enums/State.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/enums/State.java new file mode 100644 index 0000000000..11f49d5647 --- /dev/null +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/enums/State.java @@ -0,0 +1,18 @@ +package com.provectus.kafka.ui.utilities.qase.enums; + +public enum State { + + NOT_AUTOMATED(0), + TO_BE_AUTOMATED(1), + AUTOMATED(2); + + private final int value; + + State(int value) { + this.value = value; + } + + public int getValue() { + return value; + } +} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/enums/Status.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/enums/Status.java new file mode 100644 index 0000000000..a4e7e0cce3 --- /dev/null +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/enums/Status.java @@ -0,0 +1,18 @@ +package com.provectus.kafka.ui.utilities.qase.enums; + +public enum Status { + + ACTUAL(0), + DRAFT(1), + DEPRECATED(2); + + private final int value; + + Status(int value) { + this.value = value; + } + + public int getValue() { + return value; + } +} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/QaseSetup.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/QaseSetup.java deleted file mode 100644 index 60be014a0a..0000000000 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/QaseSetup.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.provectus.kafka.ui.utilities.qaseUtils; - -import lombok.extern.slf4j.Slf4j; - -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; - -import static com.provectus.kafka.ui.settings.BaseSource.SUITE_NAME; -import static com.provectus.kafka.ui.variables.Suite.MANUAL; -import static org.apache.commons.lang3.BooleanUtils.FALSE; -import static org.apache.commons.lang3.BooleanUtils.TRUE; -import static org.apache.commons.lang3.StringUtils.isEmpty; - -@Slf4j -public class QaseSetup { - - public static void qaseIntegrationSetup() { - String qaseApiToken = System.getProperty("QASEIO_API_TOKEN"); - if (isEmpty(qaseApiToken)) { - log.warn("Integration with Qase is disabled due to run config or token wasn't defined."); - System.setProperty("QASE_ENABLE", FALSE); - } else { - log.warn("Integration with Qase is enabled. Find this run at https://app.qase.io/run/KAFKAUI."); - String automation = SUITE_NAME.equalsIgnoreCase(MANUAL) ? "" : "Automation "; - System.setProperty("QASE_ENABLE", TRUE); - System.setProperty("QASE_PROJECT_CODE", "KAFKAUI"); - System.setProperty("QASE_API_TOKEN", qaseApiToken); - System.setProperty("QASE_USE_BULK", TRUE); - System.setProperty("QASE_RUN_NAME", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm") - .format(OffsetDateTime.now(ZoneOffset.UTC)) + ": " + automation + SUITE_NAME.toUpperCase() + " suite"); - } - } -} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/enums/State.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/enums/State.java deleted file mode 100644 index cdbbaf38de..0000000000 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/enums/State.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.provectus.kafka.ui.utilities.qaseUtils.enums; - -public enum State { - - NOT_AUTOMATED(0), - TO_BE_AUTOMATED(1), - AUTOMATED(2); - - private final int value; - - State(int value) { - this.value = value; - } - - public int getValue() { - return value; - } -} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/enums/Status.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/enums/Status.java deleted file mode 100644 index adc8bf24b9..0000000000 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/enums/Status.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.provectus.kafka.ui.utilities.qaseUtils.enums; - -public enum Status { - - ACTUAL(0), - DRAFT(1), - DEPRECATED(2); - - private final int value; - - Status(int value) { - this.value = value; - } - - public int getValue() { - return value; - } -} diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Browser.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Browser.java index cb3873cdb5..f435dcbf01 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Browser.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Browser.java @@ -2,6 +2,6 @@ package com.provectus.kafka.ui.variables; public interface Browser { - String CONTAINER = "container"; - String LOCAL = "local"; + String CONTAINER = "container"; + String LOCAL = "local"; } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Suite.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Suite.java index 74f60dd0d2..3d337548c9 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Suite.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Suite.java @@ -2,9 +2,9 @@ package com.provectus.kafka.ui.variables; public interface Suite { - String CUSTOM = "custom"; - String MANUAL = "manual"; - String REGRESSION = "regression"; - String SANITY = "sanity"; - String SMOKE = "smoke"; + String CUSTOM = "custom"; + String MANUAL = "manual"; + String REGRESSION = "regression"; + String SANITY = "sanity"; + String SMOKE = "smoke"; } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Url.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Url.java index f612d743a5..5b800608f3 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Url.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Url.java @@ -1,11 +1,11 @@ package com.provectus.kafka.ui.variables; public interface Url { - - String BROKERS_LIST_URL = "http://%s:8080/ui/clusters/local/brokers"; - String TOPICS_LIST_URL = "http://%s:8080/ui/clusters/local/all-topics?perPage=25"; - String CONSUMERS_LIST_URL = "http://%s:8080/ui/clusters/local/consumer-groups"; - String SCHEMA_REGISTRY_LIST_URL = "http://%s:8080/ui/clusters/local/schemas"; - String KAFKA_CONNECT_LIST_URL = "http://%s:8080/ui/clusters/local/connectors"; - String KSQL_DB_LIST_URL = "http://%s:8080/ui/clusters/local/ksqldb/tables"; + + String BROKERS_LIST_URL = "http://%s:8080/ui/clusters/local/brokers"; + String TOPICS_LIST_URL = "http://%s:8080/ui/clusters/local/all-topics"; + String CONSUMERS_LIST_URL = "http://%s:8080/ui/clusters/local/consumer-groups"; + String SCHEMA_REGISTRY_LIST_URL = "http://%s:8080/ui/clusters/local/schemas"; + String KAFKA_CONNECT_LIST_URL = "http://%s:8080/ui/clusters/local/connectors"; + String KSQL_DB_LIST_URL = "http://%s:8080/ui/clusters/local/ksqldb/tables"; } diff --git a/kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector.json b/kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector.json index fbe9fea655..096d4191e4 100644 --- a/kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector.json +++ b/kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector.json @@ -15,4 +15,4 @@ "insert.mode": "upsert", "errors.log.enable": "true", "errors.log.include.messages": "true" -} \ No newline at end of file +} diff --git a/kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector_via_api.json b/kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector_via_api.json index 5c5b7aba84..dffd66cae5 100644 --- a/kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector_via_api.json +++ b/kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector_via_api.json @@ -4,4 +4,4 @@ "connection.user": "dev_user", "connection.password": "12345", "topics": "topic_for_connector" -} \ No newline at end of file +} diff --git a/kafka-ui-e2e-checks/src/main/resources/testData/connectors/delete_connector_config.json b/kafka-ui-e2e-checks/src/main/resources/testData/connectors/delete_connector_config.json index c5adc99444..121613fc1c 100644 --- a/kafka-ui-e2e-checks/src/main/resources/testData/connectors/delete_connector_config.json +++ b/kafka-ui-e2e-checks/src/main/resources/testData/connectors/delete_connector_config.json @@ -15,4 +15,4 @@ "insert.mode": "upsert", "errors.log.enable": "true", "errors.log.include.messages": "true" -} \ No newline at end of file +} diff --git a/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_for_update.json b/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_for_update.json index 9971559ba7..bbfe011c9f 100644 --- a/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_for_update.json +++ b/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_for_update.json @@ -14,4 +14,4 @@ "default": null } ] -} \ No newline at end of file +} diff --git a/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_value.json b/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_value.json index 1bc30f6d1c..d84caf2ea8 100644 --- a/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_value.json +++ b/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_value.json @@ -12,4 +12,4 @@ "type": "int" } ] -} \ No newline at end of file +} diff --git a/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_json_Value.json b/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_json_Value.json index 5c5b7aba84..dffd66cae5 100644 --- a/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_json_Value.json +++ b/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_json_Value.json @@ -4,4 +4,4 @@ "connection.user": "dev_user", "connection.password": "12345", "topics": "topic_for_connector" -} \ No newline at end of file +} diff --git a/kafka-ui-e2e-checks/src/main/resources/testData/topics/message_content_create_topic.json b/kafka-ui-e2e-checks/src/main/resources/testData/topics/message_content_create_topic.json index 8c8fabe5bf..a4c0d940f4 100644 --- a/kafka-ui-e2e-checks/src/main/resources/testData/topics/message_content_create_topic.json +++ b/kafka-ui-e2e-checks/src/main/resources/testData/topics/message_content_create_topic.json @@ -21,4 +21,4 @@ "id":"1", "value":"kafka" } -} \ No newline at end of file +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/BaseTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/BaseTest.java index dfb4230001..45daf6a4b5 100644 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/BaseTest.java +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/BaseTest.java @@ -1,207 +1,153 @@ package com.provectus.kafka.ui; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.BROKERS; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.CONSUMERS; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.KAFKA_CONNECT; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.KSQL_DB; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.SCHEMA_REGISTRY; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.TOPICS; +import static com.provectus.kafka.ui.settings.BaseSource.BASE_UI_URL; +import static com.provectus.kafka.ui.settings.drivers.WebDriver.browserClear; +import static com.provectus.kafka.ui.settings.drivers.WebDriver.browserQuit; +import static com.provectus.kafka.ui.settings.drivers.WebDriver.browserSetup; +import static com.provectus.kafka.ui.settings.drivers.WebDriver.loggerSetup; +import static com.provectus.kafka.ui.utilities.qase.QaseSetup.qaseIntegrationSetup; + import com.codeborne.selenide.Condition; import com.codeborne.selenide.Selenide; import com.codeborne.selenide.SelenideElement; -import com.codeborne.selenide.WebDriverRunner; import com.provectus.kafka.ui.settings.listeners.AllureListener; import com.provectus.kafka.ui.settings.listeners.LoggerListener; import com.provectus.kafka.ui.settings.listeners.QaseResultListener; import io.qameta.allure.Step; -import lombok.extern.slf4j.Slf4j; -import org.openqa.selenium.Dimension; -import org.openqa.selenium.chrome.ChromeOptions; -import org.openqa.selenium.remote.RemoteWebDriver; -import org.testcontainers.Testcontainers; -import org.testcontainers.containers.BrowserWebDriverContainer; -import org.testcontainers.containers.output.Slf4jLogConsumer; -import org.testcontainers.utility.DockerImageName; -import org.testng.annotations.*; -import org.testng.asserts.SoftAssert; - -import java.time.Duration; import java.util.List; - -import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.*; -import static com.provectus.kafka.ui.settings.BaseSource.*; -import static com.provectus.kafka.ui.settings.drivers.LocalWebDriver.*; -import static com.provectus.kafka.ui.utilities.qaseUtils.QaseSetup.qaseIntegrationSetup; -import static com.provectus.kafka.ui.variables.Browser.CONTAINER; -import static com.provectus.kafka.ui.variables.Browser.LOCAL; +import lombok.extern.slf4j.Slf4j; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Listeners; +import org.testng.asserts.SoftAssert; @Slf4j @Listeners({AllureListener.class, LoggerListener.class, QaseResultListener.class}) public abstract class BaseTest extends Facade { - private static final String SELENIUM_IMAGE_NAME = "selenium/standalone-chrome:103.0"; - private static final String SELENIARM_STANDALONE_CHROMIUM = "seleniarm/standalone-chromium:103.0"; - protected static BrowserWebDriverContainer webDriverContainer = null; + @BeforeSuite(alwaysRun = true) + public void beforeSuite() { + qaseIntegrationSetup(); + loggerSetup(); + browserSetup(); + } - private static boolean isARM64() { - return System.getProperty("os.arch").equals("aarch64"); - } + @AfterSuite(alwaysRun = true) + public void afterSuite() { + browserQuit(); + } - @BeforeSuite(alwaysRun = true) - public void beforeSuite() { - qaseIntegrationSetup(); - switch (BROWSER) { - case (CONTAINER) -> { - DockerImageName image = isARM64() - ? DockerImageName.parse(SELENIARM_STANDALONE_CHROMIUM).asCompatibleSubstituteFor(SELENIUM_IMAGE_NAME) - : DockerImageName.parse(SELENIUM_IMAGE_NAME); - log.info("Using [{}] as image name for chrome", image.getUnversionedPart()); - webDriverContainer = new BrowserWebDriverContainer<>(image) - .withEnv("JAVA_OPTS", "-Dwebdriver.chrome.whitelistedIps=") - .withStartupTimeout(Duration.ofSeconds(180)) - .withCapabilities(new ChromeOptions() - .addArguments("--disable-dev-shm-usage") - .addArguments("--disable-gpu") - .addArguments("--no-sandbox") - .addArguments("--verbose") - .addArguments("--lang=es") - ) - .withLogConsumer(new Slf4jLogConsumer(log).withPrefix("[CHROME]: ")); - try { - Testcontainers.exposeHostPorts(8080); - log.info("Starting browser container"); - webDriverContainer.start(); - } catch (Throwable e) { - log.error("Couldn't start a container", e); - } - } - case (LOCAL) -> loggerSetup(); - default -> throw new IllegalStateException("Unexpected value: " + BROWSER); - } - } + @BeforeMethod(alwaysRun = true) + public void beforeMethod() { + Selenide.open(BASE_UI_URL); + naviSideBar.waitUntilScreenReady(); + } - @AfterSuite(alwaysRun = true) - public void afterSuite() { - switch (BROWSER) { - case (CONTAINER) -> { - if (webDriverContainer.isRunning()) { - webDriverContainer.close(); - webDriverContainer.stop(); - } - } - case (LOCAL) -> browserQuit(); - default -> throw new IllegalStateException("Unexpected value: " + BROWSER); - } - } + @AfterMethod(alwaysRun = true) + public void afterMethod() { + browserClear(); + } - @BeforeMethod(alwaysRun = true) - public void beforeMethod() { - switch (BROWSER) { - case (CONTAINER) -> { - RemoteWebDriver remoteWebDriver = webDriverContainer.getWebDriver(); - WebDriverRunner.setWebDriver(remoteWebDriver); - remoteWebDriver.manage() - .window().setSize(new Dimension(1440, 1024)); - Selenide.open(BASE_CONTAINER_URL); - } - case (LOCAL) -> openUrl(BASE_LOCAL_URL); - default -> throw new IllegalStateException("Unexpected value: " + BROWSER); - } - naviSideBar.waitUntilScreenReady(); - } + @Step + protected void navigateToBrokers() { + naviSideBar + .openSideMenu(BROKERS); + brokersList + .waitUntilScreenReady(); + } - @AfterMethod(alwaysRun = true) - public void afterMethod() { - browserClear(); - } + @Step + protected void navigateToBrokersAndOpenDetails(int brokerId) { + naviSideBar + .openSideMenu(BROKERS); + brokersList + .waitUntilScreenReady() + .openBroker(brokerId); + brokersDetails + .waitUntilScreenReady(); + } - @Step - protected void navigateToBrokers() { - naviSideBar - .openSideMenu(BROKERS); - brokersList - .waitUntilScreenReady(); - } + @Step + protected void navigateToTopics() { + naviSideBar + .openSideMenu(TOPICS); + topicsList + .waitUntilScreenReady() + .setShowInternalRadioButton(false); + } - @Step - protected void navigateToBrokersAndOpenDetails(int brokerId) { - naviSideBar - .openSideMenu(BROKERS); - brokersList - .waitUntilScreenReady() - .openBroker(brokerId); - brokersDetails - .waitUntilScreenReady(); - } + @Step + protected void navigateToTopicsAndOpenDetails(String topicName) { + navigateToTopics(); + topicsList + .openTopic(topicName); + topicDetails + .waitUntilScreenReady(); + } - @Step - protected void navigateToTopics() { - naviSideBar - .openSideMenu(TOPICS); - topicsList - .waitUntilScreenReady(); - } + @Step + protected void navigateToConsumers() { + naviSideBar + .openSideMenu(CONSUMERS); + consumersList + .waitUntilScreenReady(); + } - @Step - protected void navigateToTopicsAndOpenDetails(String topicName) { - naviSideBar - .openSideMenu(TOPICS); - topicsList - .waitUntilScreenReady() - .openTopic(topicName); - topicDetails - .waitUntilScreenReady(); - } + @Step + protected void navigateToSchemaRegistry() { + naviSideBar + .openSideMenu(SCHEMA_REGISTRY); + schemaRegistryList + .waitUntilScreenReady(); + } - @Step - protected void navigateToConsumers() { - naviSideBar - .openSideMenu(CONSUMERS); - consumersList - .waitUntilScreenReady(); - } + @Step + protected void navigateToSchemaRegistryAndOpenDetails(String schemaName) { + navigateToSchemaRegistry(); + schemaRegistryList + .openSchema(schemaName); + schemaDetails + .waitUntilScreenReady(); + } - @Step - protected void navigateToSchemaRegistry() { - naviSideBar - .openSideMenu(SCHEMA_REGISTRY); - schemaRegistryList - .waitUntilScreenReady(); - } + @Step + protected void navigateToConnectors() { + naviSideBar + .openSideMenu(KAFKA_CONNECT); + kafkaConnectList + .waitUntilScreenReady(); + } - @Step - protected void navigateToSchemaRegistryAndOpenDetails(String schemaName) { - navigateToSchemaRegistry(); - schemaRegistryList - .openSchema(schemaName); - schemaDetails - .waitUntilScreenReady(); - } + @Step + protected void navigateToConnectorsAndOpenDetails(String connectorName) { + navigateToConnectors(); + kafkaConnectList + .openConnector(connectorName); + connectorDetails + .waitUntilScreenReady(); + } - @Step - protected void navigateToConnectors() { - naviSideBar - .openSideMenu(KAFKA_CONNECT); - kafkaConnectList - .waitUntilScreenReady(); - } + @Step + protected void navigateToKsqlDb() { + naviSideBar + .openSideMenu(KSQL_DB); + ksqlDbList + .waitUntilScreenReady(); + } - @Step - protected void navigateToConnectorsAndOpenDetails(String connectorName) { - navigateToConnectors(); - kafkaConnectList - .openConnector(connectorName); - connectorDetails - .waitUntilScreenReady(); - } - - @Step - protected void navigateToKsqlDb() { - naviSideBar - .openSideMenu(KSQL_DB); - ksqlDbList - .waitUntilScreenReady(); - } - - @Step - protected void verifyElementsCondition(List elementList, Condition expectedCondition) { - SoftAssert softly = new SoftAssert(); - elementList.forEach(element -> softly.assertTrue(element.is(expectedCondition), - element.getSearchCriteria() + " is " + expectedCondition)); - softly.assertAll(); - } + @Step + protected void verifyElementsCondition(List elementList, Condition expectedCondition) { + SoftAssert softly = new SoftAssert(); + elementList.forEach(element -> softly.assertTrue(element.is(expectedCondition), + element.getSearchCriteria() + " is " + expectedCondition)); + softly.assertAll(); + } } diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/Facade.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/Facade.java index 67468dbcb0..abc0b0aa6b 100644 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/Facade.java +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/Facade.java @@ -1,7 +1,5 @@ package com.provectus.kafka.ui; -import com.provectus.kafka.ui.pages.panels.NaviSideBar; -import com.provectus.kafka.ui.pages.panels.TopPanel; import com.provectus.kafka.ui.pages.brokers.BrokersConfigTab; import com.provectus.kafka.ui.pages.brokers.BrokersDetails; import com.provectus.kafka.ui.pages.brokers.BrokersList; @@ -10,35 +8,41 @@ import com.provectus.kafka.ui.pages.connectors.ConnectorDetails; import com.provectus.kafka.ui.pages.connectors.KafkaConnectList; import com.provectus.kafka.ui.pages.consumers.ConsumersDetails; import com.provectus.kafka.ui.pages.consumers.ConsumersList; -import com.provectus.kafka.ui.pages.ksqlDb.KsqlDbList; -import com.provectus.kafka.ui.pages.ksqlDb.KsqlQueryForm; +import com.provectus.kafka.ui.pages.ksqldb.KsqlDbList; +import com.provectus.kafka.ui.pages.ksqldb.KsqlQueryForm; +import com.provectus.kafka.ui.pages.panels.NaviSideBar; +import com.provectus.kafka.ui.pages.panels.TopPanel; import com.provectus.kafka.ui.pages.schemas.SchemaCreateForm; import com.provectus.kafka.ui.pages.schemas.SchemaDetails; import com.provectus.kafka.ui.pages.schemas.SchemaRegistryList; -import com.provectus.kafka.ui.pages.topics.*; +import com.provectus.kafka.ui.pages.topics.ProduceMessagePanel; +import com.provectus.kafka.ui.pages.topics.TopicCreateEditForm; +import com.provectus.kafka.ui.pages.topics.TopicDetails; +import com.provectus.kafka.ui.pages.topics.TopicSettingsTab; +import com.provectus.kafka.ui.pages.topics.TopicsList; import com.provectus.kafka.ui.services.ApiService; public abstract class Facade { - protected ApiService apiService = new ApiService(); - protected ConnectorCreateForm connectorCreateForm = new ConnectorCreateForm(); - protected KafkaConnectList kafkaConnectList = new KafkaConnectList(); - protected ConnectorDetails connectorDetails = new ConnectorDetails(); - protected SchemaCreateForm schemaCreateForm = new SchemaCreateForm(); - protected SchemaDetails schemaDetails = new SchemaDetails(); - protected SchemaRegistryList schemaRegistryList = new SchemaRegistryList(); - protected ProduceMessagePanel produceMessagePanel = new ProduceMessagePanel(); - protected TopicCreateEditForm topicCreateEditForm = new TopicCreateEditForm(); - protected TopicsList topicsList = new TopicsList(); - protected TopicDetails topicDetails = new TopicDetails(); - protected ConsumersDetails consumersDetails = new ConsumersDetails(); - protected ConsumersList consumersList = new ConsumersList(); - protected NaviSideBar naviSideBar = new NaviSideBar(); - protected TopPanel topPanel = new TopPanel(); - protected BrokersList brokersList = new BrokersList(); - protected BrokersDetails brokersDetails = new BrokersDetails(); - protected BrokersConfigTab brokersConfigTab = new BrokersConfigTab(); - protected TopicSettingsTab topicSettingsTab = new TopicSettingsTab(); - protected KsqlQueryForm ksqlQueryForm = new KsqlQueryForm(); - protected KsqlDbList ksqlDbList = new KsqlDbList(); + protected ApiService apiService = new ApiService(); + protected ConnectorCreateForm connectorCreateForm = new ConnectorCreateForm(); + protected KafkaConnectList kafkaConnectList = new KafkaConnectList(); + protected ConnectorDetails connectorDetails = new ConnectorDetails(); + protected SchemaCreateForm schemaCreateForm = new SchemaCreateForm(); + protected SchemaDetails schemaDetails = new SchemaDetails(); + protected SchemaRegistryList schemaRegistryList = new SchemaRegistryList(); + protected ProduceMessagePanel produceMessagePanel = new ProduceMessagePanel(); + protected TopicCreateEditForm topicCreateEditForm = new TopicCreateEditForm(); + protected TopicsList topicsList = new TopicsList(); + protected TopicDetails topicDetails = new TopicDetails(); + protected ConsumersDetails consumersDetails = new ConsumersDetails(); + protected ConsumersList consumersList = new ConsumersList(); + protected NaviSideBar naviSideBar = new NaviSideBar(); + protected TopPanel topPanel = new TopPanel(); + protected BrokersList brokersList = new BrokersList(); + protected BrokersDetails brokersDetails = new BrokersDetails(); + protected BrokersConfigTab brokersConfigTab = new BrokersConfigTab(); + protected TopicSettingsTab topicSettingsTab = new TopicSettingsTab(); + protected KsqlQueryForm ksqlQueryForm = new KsqlQueryForm(); + protected KsqlDbList ksqlDbList = new KsqlDbList(); } diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/BaseManualTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/BaseManualTest.java deleted file mode 100644 index bf9f0c75ac..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/BaseManualTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.provectus.kafka.ui.manualSuite; - -import com.provectus.kafka.ui.settings.listeners.QaseResultListener; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Automation; -import org.testng.SkipException; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.BeforeSuite; -import org.testng.annotations.Listeners; - -import java.lang.reflect.Method; - -import static com.provectus.kafka.ui.utilities.qaseUtils.QaseSetup.qaseIntegrationSetup; -import static com.provectus.kafka.ui.utilities.qaseUtils.enums.State.NOT_AUTOMATED; -import static com.provectus.kafka.ui.utilities.qaseUtils.enums.State.TO_BE_AUTOMATED; - -@Listeners(QaseResultListener.class) -public abstract class BaseManualTest { - - @BeforeSuite - public void beforeSuite() { - qaseIntegrationSetup(); - } - - @BeforeMethod - public void beforeMethod(Method method) { - if (method.getAnnotation(Automation.class).state().equals(NOT_AUTOMATED) - || method.getAnnotation(Automation.class).state().equals(TO_BE_AUTOMATED)) - throw new SkipException("Skip test exception"); - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/backlog/SanityBacklog.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/backlog/SanityBacklog.java deleted file mode 100644 index f09673c8a0..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/backlog/SanityBacklog.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.provectus.kafka.ui.manualSuite.backlog; - -import com.provectus.kafka.ui.manualSuite.BaseManualTest; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Automation; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Suite; -import io.qase.api.annotation.QaseId; -import org.testng.annotations.Test; - -import static com.provectus.kafka.ui.utilities.qaseUtils.enums.State.TO_BE_AUTOMATED; - -public class SanityBacklog extends BaseManualTest { - - @Automation(state = TO_BE_AUTOMATED) - @Suite(id = 19) - @QaseId(285) - @Test - public void testCaseA() { - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/backlog/SmokeBacklog.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/backlog/SmokeBacklog.java deleted file mode 100644 index 84fa7476cf..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/backlog/SmokeBacklog.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.provectus.kafka.ui.manualSuite.backlog; - -import com.provectus.kafka.ui.manualSuite.BaseManualTest; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Automation; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Suite; -import io.qase.api.annotation.QaseId; -import org.testng.annotations.Test; - -import static com.provectus.kafka.ui.utilities.qaseUtils.enums.State.TO_BE_AUTOMATED; - -public class SmokeBacklog extends BaseManualTest { - - @Automation(state = TO_BE_AUTOMATED) - @Suite(id = 1) - @QaseId(330) - @Test - public void testCaseA() { - } - - @Automation(state = TO_BE_AUTOMATED) - @Suite(id = 8) - @QaseId(276) - @Test - public void testCaseB() { - } - - @Automation(state = TO_BE_AUTOMATED) - @Suite(id = 8) - @QaseId(277) - @Test - public void testCaseC() { - } - - @Automation(state = TO_BE_AUTOMATED) - @Suite(id = 8) - @QaseId(278) - @Test - public void testCaseD() { - } - - @Automation(state = TO_BE_AUTOMATED) - @Suite(id = 8) - @QaseId(284) - @Test - public void testCaseE() { - } - - @Automation(state = TO_BE_AUTOMATED) - @Suite(id = 1) - @QaseId(331) - @Test - public void testCaseF() { - } - - @Automation(state = TO_BE_AUTOMATED) - @Suite(id = 1) - @QaseId(332) - @Test - public void testCaseG() { - } - - @Automation(state = TO_BE_AUTOMATED) - @Suite(id = 5) - @QaseId(335) - @Test - public void testCaseH() { - } - - @Automation(state = TO_BE_AUTOMATED) - @Suite(id = 5) - @QaseId(336) - @Test - public void testCaseI() { - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/suite/DataMaskingTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/suite/DataMaskingTest.java deleted file mode 100644 index 23b6e6539e..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/suite/DataMaskingTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.provectus.kafka.ui.manualSuite.suite; - -import com.provectus.kafka.ui.manualSuite.BaseManualTest; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Automation; -import io.qase.api.annotation.QaseId; -import org.testng.annotations.Test; - -import static com.provectus.kafka.ui.utilities.qaseUtils.enums.State.NOT_AUTOMATED; - -public class DataMaskingTest extends BaseManualTest { - - @Automation(state = NOT_AUTOMATED) - @QaseId(262) - @Test - public void testCaseA() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(264) - @Test - public void testCaseB() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(265) - @Test - public void testCaseC() { - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/suite/RbacTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/suite/RbacTest.java deleted file mode 100644 index aad85652f5..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/suite/RbacTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.provectus.kafka.ui.manualSuite.suite; - -import com.provectus.kafka.ui.manualSuite.BaseManualTest; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Automation; -import io.qase.api.annotation.QaseId; -import org.testng.annotations.Test; - -import static com.provectus.kafka.ui.utilities.qaseUtils.enums.State.NOT_AUTOMATED; - -public class RbacTest extends BaseManualTest { - - @Automation(state = NOT_AUTOMATED) - @QaseId(249) - @Test - public void testCaseA() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(251) - @Test - public void testCaseB() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(257) - @Test - public void testCaseC() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(258) - @Test - public void testCaseD() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(259) - @Test - public void testCaseE() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(260) - @Test - public void testCaseF() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(261) - @Test - public void testCaseG() { - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/suite/TopicsTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/suite/TopicsTest.java deleted file mode 100644 index dda8103ffa..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/suite/TopicsTest.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.provectus.kafka.ui.manualSuite.suite; - -import com.provectus.kafka.ui.manualSuite.BaseManualTest; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Automation; -import io.qase.api.annotation.QaseId; -import org.testng.annotations.Test; - -import static com.provectus.kafka.ui.utilities.qaseUtils.enums.State.NOT_AUTOMATED; - -public class TopicsTest extends BaseManualTest { - - @Automation(state = NOT_AUTOMATED) - @QaseId(17) - @Test - public void testCaseA() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(18) - @Test - public void testCaseB() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(21) - @Test() - public void testCaseC() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(22) - @Test - public void testCaseD() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(47) - @Test - public void testCaseE() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(48) - @Test - public void testCaseF() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(49) - @Test - public void testCaseG() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(50) - @Test - public void testCaseH() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(57) - @Test - public void testCaseI() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(58) - @Test - public void testCaseJ() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(269) - @Test - public void testCaseK() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(270) - @Test - public void testCaseL() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(271) - @Test - public void testCaseM() { - } - - @Automation(state = NOT_AUTOMATED) - @QaseId(272) - @Test - public void testCaseN() { - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/suite/WizardTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/suite/WizardTest.java deleted file mode 100644 index e7ae52bdb1..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualSuite/suite/WizardTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.provectus.kafka.ui.manualSuite.suite; - -import com.provectus.kafka.ui.manualSuite.BaseManualTest; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Automation; -import io.qase.api.annotation.QaseId; -import org.testng.annotations.Test; - -import static com.provectus.kafka.ui.utilities.qaseUtils.enums.State.NOT_AUTOMATED; - -public class WizardTest extends BaseManualTest { - - @Automation(state = NOT_AUTOMATED) - @QaseId(333) - @Test - public void testCaseA() { - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/BaseManualTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/BaseManualTest.java new file mode 100644 index 0000000000..827dc1ce43 --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/BaseManualTest.java @@ -0,0 +1,30 @@ +package com.provectus.kafka.ui.manualsuite; + +import static com.provectus.kafka.ui.utilities.qase.QaseSetup.qaseIntegrationSetup; +import static com.provectus.kafka.ui.utilities.qase.enums.State.NOT_AUTOMATED; +import static com.provectus.kafka.ui.utilities.qase.enums.State.TO_BE_AUTOMATED; + +import com.provectus.kafka.ui.settings.listeners.QaseResultListener; +import com.provectus.kafka.ui.utilities.qase.annotations.Automation; +import java.lang.reflect.Method; +import org.testng.SkipException; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Listeners; + +@Listeners(QaseResultListener.class) +public abstract class BaseManualTest { + + @BeforeSuite + public void beforeSuite() { + qaseIntegrationSetup(); + } + + @BeforeMethod + public void beforeMethod(Method method) { + if (method.getAnnotation(Automation.class).state().equals(NOT_AUTOMATED) + || method.getAnnotation(Automation.class).state().equals(TO_BE_AUTOMATED)) { + throw new SkipException("Skip test exception"); + } + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/backlog/SanityBacklog.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/backlog/SanityBacklog.java new file mode 100644 index 0000000000..4021c8ec94 --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/backlog/SanityBacklog.java @@ -0,0 +1,7 @@ +package com.provectus.kafka.ui.manualsuite.backlog; + +import com.provectus.kafka.ui.manualsuite.BaseManualTest; + +public class SanityBacklog extends BaseManualTest { + +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/backlog/SmokeBacklog.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/backlog/SmokeBacklog.java new file mode 100644 index 0000000000..b89a1d0cf7 --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/backlog/SmokeBacklog.java @@ -0,0 +1,78 @@ +package com.provectus.kafka.ui.manualsuite.backlog; + +import static com.provectus.kafka.ui.qasesuite.BaseQaseTest.BROKERS_SUITE_ID; +import static com.provectus.kafka.ui.qasesuite.BaseQaseTest.KSQL_DB_SUITE_ID; +import static com.provectus.kafka.ui.qasesuite.BaseQaseTest.TOPICS_PROFILE_SUITE_ID; +import static com.provectus.kafka.ui.utilities.qase.enums.State.TO_BE_AUTOMATED; + +import com.provectus.kafka.ui.manualsuite.BaseManualTest; +import com.provectus.kafka.ui.utilities.qase.annotations.Automation; +import com.provectus.kafka.ui.utilities.qase.annotations.Suite; +import io.qase.api.annotation.QaseId; +import org.testng.annotations.Test; + +public class SmokeBacklog extends BaseManualTest { + + @Automation(state = TO_BE_AUTOMATED) + @Suite(id = BROKERS_SUITE_ID) + @QaseId(330) + @Test + public void testCaseA() { + } + + @Automation(state = TO_BE_AUTOMATED) + @Suite(id = KSQL_DB_SUITE_ID) + @QaseId(276) + @Test + public void testCaseB() { + } + + @Automation(state = TO_BE_AUTOMATED) + @Suite(id = KSQL_DB_SUITE_ID) + @QaseId(277) + @Test + public void testCaseC() { + } + + @Automation(state = TO_BE_AUTOMATED) + @Suite(id = KSQL_DB_SUITE_ID) + @QaseId(278) + @Test + public void testCaseD() { + } + + @Automation(state = TO_BE_AUTOMATED) + @Suite(id = KSQL_DB_SUITE_ID) + @QaseId(284) + @Test + public void testCaseE() { + } + + @Automation(state = TO_BE_AUTOMATED) + @Suite(id = BROKERS_SUITE_ID) + @QaseId(331) + @Test + public void testCaseF() { + } + + @Automation(state = TO_BE_AUTOMATED) + @Suite(id = BROKERS_SUITE_ID) + @QaseId(332) + @Test + public void testCaseG() { + } + + @Automation(state = TO_BE_AUTOMATED) + @Suite(id = TOPICS_PROFILE_SUITE_ID) + @QaseId(335) + @Test + public void testCaseH() { + } + + @Automation(state = TO_BE_AUTOMATED) + @Suite(id = TOPICS_PROFILE_SUITE_ID) + @QaseId(336) + @Test + public void testCaseI() { + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/suite/DataMaskingTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/suite/DataMaskingTest.java new file mode 100644 index 0000000000..540511d0c4 --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/suite/DataMaskingTest.java @@ -0,0 +1,29 @@ +package com.provectus.kafka.ui.manualsuite.suite; + +import static com.provectus.kafka.ui.utilities.qase.enums.State.NOT_AUTOMATED; + +import com.provectus.kafka.ui.manualsuite.BaseManualTest; +import com.provectus.kafka.ui.utilities.qase.annotations.Automation; +import io.qase.api.annotation.QaseId; +import org.testng.annotations.Test; + +public class DataMaskingTest extends BaseManualTest { + + @Automation(state = NOT_AUTOMATED) + @QaseId(262) + @Test + public void testCaseA() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(264) + @Test + public void testCaseB() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(265) + @Test + public void testCaseC() { + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/suite/RbacTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/suite/RbacTest.java new file mode 100644 index 0000000000..7c7ac3153b --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/suite/RbacTest.java @@ -0,0 +1,53 @@ +package com.provectus.kafka.ui.manualsuite.suite; + +import static com.provectus.kafka.ui.utilities.qase.enums.State.NOT_AUTOMATED; + +import com.provectus.kafka.ui.manualsuite.BaseManualTest; +import com.provectus.kafka.ui.utilities.qase.annotations.Automation; +import io.qase.api.annotation.QaseId; +import org.testng.annotations.Test; + +public class RbacTest extends BaseManualTest { + + @Automation(state = NOT_AUTOMATED) + @QaseId(249) + @Test + public void testCaseA() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(251) + @Test + public void testCaseB() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(257) + @Test + public void testCaseC() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(258) + @Test + public void testCaseD() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(259) + @Test + public void testCaseE() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(260) + @Test + public void testCaseF() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(261) + @Test + public void testCaseG() { + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/suite/TopicsTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/suite/TopicsTest.java new file mode 100644 index 0000000000..76f8506deb --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/suite/TopicsTest.java @@ -0,0 +1,95 @@ +package com.provectus.kafka.ui.manualsuite.suite; + +import static com.provectus.kafka.ui.utilities.qase.enums.State.NOT_AUTOMATED; + +import com.provectus.kafka.ui.manualsuite.BaseManualTest; +import com.provectus.kafka.ui.utilities.qase.annotations.Automation; +import io.qase.api.annotation.QaseId; +import org.testng.annotations.Test; + +public class TopicsTest extends BaseManualTest { + + @Automation(state = NOT_AUTOMATED) + @QaseId(17) + @Test + public void testCaseA() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(18) + @Test + public void testCaseB() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(21) + @Test() + public void testCaseC() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(22) + @Test + public void testCaseD() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(47) + @Test + public void testCaseE() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(48) + @Test + public void testCaseF() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(49) + @Test + public void testCaseG() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(50) + @Test + public void testCaseH() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(57) + @Test + public void testCaseI() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(58) + @Test + public void testCaseJ() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(269) + @Test + public void testCaseK() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(270) + @Test + public void testCaseL() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(271) + @Test + public void testCaseM() { + } + + @Automation(state = NOT_AUTOMATED) + @QaseId(272) + @Test + public void testCaseN() { + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/suite/WizardTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/suite/WizardTest.java new file mode 100644 index 0000000000..9621104b1a --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/manualsuite/suite/WizardTest.java @@ -0,0 +1,17 @@ +package com.provectus.kafka.ui.manualsuite.suite; + +import static com.provectus.kafka.ui.utilities.qase.enums.State.NOT_AUTOMATED; + +import com.provectus.kafka.ui.manualsuite.BaseManualTest; +import com.provectus.kafka.ui.utilities.qase.annotations.Automation; +import io.qase.api.annotation.QaseId; +import org.testng.annotations.Test; + +public class WizardTest extends BaseManualTest { + + @Automation(state = NOT_AUTOMATED) + @QaseId(333) + @Test + public void testCaseA() { + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qaseSuite/BaseQaseTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qaseSuite/BaseQaseTest.java deleted file mode 100644 index 7b4c34ac05..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qaseSuite/BaseQaseTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.provectus.kafka.ui.qaseSuite; - -import com.provectus.kafka.ui.settings.listeners.QaseCreateListener; -import org.testng.annotations.BeforeSuite; -import org.testng.annotations.Listeners; - -import static com.provectus.kafka.ui.utilities.qaseUtils.QaseSetup.qaseIntegrationSetup; - -@Listeners(QaseCreateListener.class) -public abstract class BaseQaseTest { - - protected static final long BROKERS_SUITE_ID = 1; - protected static final long CONNECTORS_SUITE_ID = 10; - protected static final long KSQL_DB_SUITE_ID = 8; - protected static final long SANITY_SUITE_ID = 19; - protected static final long SCHEMAS_SUITE_ID = 11; - protected static final long TOPICS_SUITE_ID = 2; - - @BeforeSuite - public void beforeSuite() { - qaseIntegrationSetup(); - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qaseSuite/Template.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qaseSuite/Template.java deleted file mode 100644 index ca987650dc..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qaseSuite/Template.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.provectus.kafka.ui.qaseSuite; - -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Automation; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Status; -import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Suite; -import io.qase.api.annotation.QaseTitle; -import io.qase.api.annotation.Step; - -import static com.provectus.kafka.ui.utilities.qaseUtils.enums.State.NOT_AUTOMATED; -import static com.provectus.kafka.ui.utilities.qaseUtils.enums.Status.DRAFT; - -public class Template extends BaseQaseTest { - - /** - * this class is a kind of placeholder or example, use is as template to create new one - * copy Template into kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qaseSuite/ - * place it into regarding folder and rename according to test case summary from Qase.io - * uncomment @Test and set all annotations according to kafka-ui-e2e-checks/QASE.md - */ - - @Automation(state = NOT_AUTOMATED) - @QaseTitle("testCaseA title") - @Status(status = DRAFT) - @Suite(id = 0) -// @org.testng.annotations.Test - public void testCaseA() { - stepA(); - stepB(); - stepC(); - stepD(); - stepE(); - stepF(); - } - - @Step("stepA action") - private void stepA() { - } - - @Step("stepB action") - private void stepB() { - } - - @Step("stepC action") - private void stepC() { - } - - @Step("stepD action") - private void stepD() { - } - - @Step("stepE action") - private void stepE() { - } - - @Step("stepF action") - private void stepF() { - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qasesuite/BaseQaseTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qasesuite/BaseQaseTest.java new file mode 100644 index 0000000000..1a195a3631 --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qasesuite/BaseQaseTest.java @@ -0,0 +1,25 @@ +package com.provectus.kafka.ui.qasesuite; + +import static com.provectus.kafka.ui.utilities.qase.QaseSetup.qaseIntegrationSetup; + +import com.provectus.kafka.ui.settings.listeners.QaseCreateListener; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Listeners; + +@Listeners(QaseCreateListener.class) +public abstract class BaseQaseTest { + + public static final long BROKERS_SUITE_ID = 1; + public static final long CONNECTORS_SUITE_ID = 10; + public static final long KSQL_DB_SUITE_ID = 8; + public static final long SANITY_SUITE_ID = 19; + public static final long SCHEMAS_SUITE_ID = 11; + public static final long TOPICS_SUITE_ID = 2; + public static final long TOPICS_CREATE_SUITE_ID = 4; + public static final long TOPICS_PROFILE_SUITE_ID = 5; + + @BeforeSuite + public void beforeSuite() { + qaseIntegrationSetup(); + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qasesuite/Template.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qasesuite/Template.java new file mode 100644 index 0000000000..d5a47eccdf --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qasesuite/Template.java @@ -0,0 +1,58 @@ +package com.provectus.kafka.ui.qasesuite; + +import static com.provectus.kafka.ui.utilities.qase.enums.State.NOT_AUTOMATED; +import static com.provectus.kafka.ui.utilities.qase.enums.Status.DRAFT; + +import com.provectus.kafka.ui.utilities.qase.annotations.Automation; +import com.provectus.kafka.ui.utilities.qase.annotations.Status; +import com.provectus.kafka.ui.utilities.qase.annotations.Suite; +import io.qase.api.annotation.QaseTitle; +import io.qase.api.annotation.Step; + +public class Template extends BaseQaseTest { + + /** + * this class is a kind of placeholder or example, use is as template to create new one + * copy Template into kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/qaseSuite/ + * place it into regarding folder and rename according to test case summary from Qase.io + * uncomment @Test and set all annotations according to kafka-ui-e2e-checks/QASE.md + */ + + @Automation(state = NOT_AUTOMATED) + @QaseTitle("testCaseA title") + @Status(status = DRAFT) + @Suite(id = 0) + // @org.testng.annotations.Test + public void testCaseA() { + stepA(); + stepB(); + stepC(); + stepD(); + stepE(); + stepF(); + } + + @Step("stepA action") + private void stepA() { + } + + @Step("stepB action") + private void stepB() { + } + + @Step("stepC action") + private void stepC() { + } + + @Step("stepD action") + private void stepD() { + } + + @Step("stepE action") + private void stepE() { + } + + @Step("stepF action") + private void stepF() { + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/sanitySuite/TestClass.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/sanitySuite/TestClass.java deleted file mode 100644 index 89402f3fc8..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/sanitySuite/TestClass.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.provectus.kafka.ui.sanitySuite; - -public class TestClass { -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/sanitysuite/TopicsTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/sanitysuite/TopicsTest.java new file mode 100644 index 0000000000..40a6d67800 --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/sanitysuite/TopicsTest.java @@ -0,0 +1,66 @@ +package com.provectus.kafka.ui.sanitysuite; + +import static com.provectus.kafka.ui.pages.topics.enums.CleanupPolicyValue.COMPACT; +import static com.provectus.kafka.ui.pages.topics.enums.CleanupPolicyValue.DELETE; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + +import com.provectus.kafka.ui.BaseTest; +import com.provectus.kafka.ui.models.Topic; +import io.qase.api.annotation.QaseId; +import java.util.ArrayList; +import java.util.List; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +public class TopicsTest extends BaseTest { + + private static final List TOPIC_LIST = new ArrayList<>(); + + @QaseId(285) + @Test() + public void verifyClearMessagesMenuStateAfterTopicUpdate() { + Topic topic = new Topic() + .setName("topic-" + randomAlphabetic(5)) + .setNumberOfPartitions(1) + .setCleanupPolicyValue(DELETE); + navigateToTopics(); + topicsList + .clickAddTopicBtn(); + topicCreateEditForm + .waitUntilScreenReady() + .setTopicName(topic.getName()) + .setNumberOfPartitions(topic.getNumberOfPartitions()) + .selectCleanupPolicy(topic.getCleanupPolicyValue()) + .clickSaveTopicBtn(); + topicDetails + .waitUntilScreenReady(); + TOPIC_LIST.add(topic); + topicDetails + .openDotMenu(); + Assert.assertTrue(topicDetails.isClearMessagesMenuEnabled(), "isClearMessagesMenuEnabled"); + topic.setCleanupPolicyValue(COMPACT); + editCleanUpPolicyAndOpenDotMenu(topic); + Assert.assertFalse(topicDetails.isClearMessagesMenuEnabled(), "isClearMessagesMenuEnabled"); + topic.setCleanupPolicyValue(DELETE); + editCleanUpPolicyAndOpenDotMenu(topic); + Assert.assertTrue(topicDetails.isClearMessagesMenuEnabled(), "isClearMessagesMenuEnabled"); + } + + private void editCleanUpPolicyAndOpenDotMenu(Topic topic) { + topicDetails + .clickEditSettingsMenu(); + topicCreateEditForm + .waitUntilScreenReady() + .selectCleanupPolicy(topic.getCleanupPolicyValue()) + .clickSaveTopicBtn(); + topicDetails + .waitUntilScreenReady() + .openDotMenu(); + } + + @AfterClass(alwaysRun = true) + public void afterClass() { + TOPIC_LIST.forEach(topic -> apiService.deleteTopic(topic.getName())); + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/SmokeTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/SmokeTest.java deleted file mode 100644 index aa48cde2fc..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/SmokeTest.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.provectus.kafka.ui.smokeSuite; - -import com.codeborne.selenide.Condition; -import com.codeborne.selenide.WebDriverRunner; -import com.provectus.kafka.ui.BaseTest; -import com.provectus.kafka.ui.pages.panels.enums.MenuItem; -import com.provectus.kafka.ui.models.Connector; -import com.provectus.kafka.ui.models.Schema; -import com.provectus.kafka.ui.models.Topic; -import io.qameta.allure.Step; -import io.qase.api.annotation.QaseId; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.*; -import static com.provectus.kafka.ui.settings.BaseSource.BROWSER; -import static com.provectus.kafka.ui.utilities.FileUtils.getResourceAsString; -import static com.provectus.kafka.ui.variables.Browser.LOCAL; -import static com.provectus.kafka.ui.variables.Url.*; -import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; - -public class SmokeTest extends BaseTest { - - private static final int BROKER_ID = 1; - private static final Schema TEST_SCHEMA = Schema.createSchemaAvro(); - private static final Topic TEST_TOPIC = new Topic() - .setName("new-topic-" + randomAlphabetic(5)) - .setNumberOfPartitions(1); - private static final Connector TEST_CONNECTOR = new Connector() - .setName("new-connector-" + randomAlphabetic(5)) - .setConfig(getResourceAsString("testData/connectors/config_for_create_connector_via_api.json")); - - @BeforeClass(alwaysRun = true) - public void beforeClass() { - apiService - .createTopic(TEST_TOPIC) - .createSchema(TEST_SCHEMA) - .createConnector(TEST_CONNECTOR); - } - - @QaseId(198) - @Test - public void checkBasePageElements() { - verifyElementsCondition( - Stream.concat(topPanel.getAllVisibleElements().stream(), naviSideBar.getAllMenuButtons().stream()) - .collect(Collectors.toList()), Condition.visible); - verifyElementsCondition( - Stream.concat(topPanel.getAllEnabledElements().stream(), naviSideBar.getAllMenuButtons().stream()) - .collect(Collectors.toList()), Condition.enabled); - } - - @QaseId(45) - @Test - public void checkUrlWhileNavigating() { - navigateToBrokers(); - verifyCurrentUrl(BROKERS_LIST_URL); - navigateToTopics(); - verifyCurrentUrl(TOPICS_LIST_URL); - navigateToConsumers(); - verifyCurrentUrl(CONSUMERS_LIST_URL); - navigateToSchemaRegistry(); - verifyCurrentUrl(SCHEMA_REGISTRY_LIST_URL); - navigateToConnectors(); - verifyCurrentUrl(KAFKA_CONNECT_LIST_URL); - navigateToKsqlDb(); - verifyCurrentUrl(KSQL_DB_LIST_URL); - } - - @QaseId(46) - @Test - public void checkComponentsPathWhileNavigating() { - navigateToBrokersAndOpenDetails(BROKER_ID); - verifyComponentsPath(BROKERS, String.format("Broker %d", BROKER_ID)); - navigateToTopicsAndOpenDetails(TEST_TOPIC.getName()); - verifyComponentsPath(TOPICS, TEST_TOPIC.getName()); - navigateToSchemaRegistryAndOpenDetails(TEST_SCHEMA.getName()); - verifyComponentsPath(SCHEMA_REGISTRY, TEST_SCHEMA.getName()); - navigateToConnectorsAndOpenDetails(TEST_CONNECTOR.getName()); - verifyComponentsPath(KAFKA_CONNECT, TEST_CONNECTOR.getName()); - } - - @Step - private void verifyCurrentUrl(String expectedUrl) { - String host = BROWSER.equals(LOCAL) ? "localhost" : "host.testcontainers.internal"; - Assert.assertEquals(WebDriverRunner.getWebDriver().getCurrentUrl(), - String.format(expectedUrl, host), "getCurrentUrl()"); - } - - @Step - private void verifyComponentsPath(MenuItem menuItem, String expectedPath) { - Assert.assertEquals(naviSideBar.getPagePath(menuItem), expectedPath, - String.format("getPagePath() for %s", menuItem.getPageTitle().toUpperCase())); - } - - @AfterClass(alwaysRun = true) - public void afterClass() { - apiService - .deleteTopic(TEST_TOPIC.getName()) - .deleteSchema(TEST_SCHEMA.getName()) - .deleteConnector(TEST_CONNECTOR.getName()); - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/brokers/BrokersTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/brokers/BrokersTest.java deleted file mode 100644 index c9029e30ae..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/brokers/BrokersTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.provectus.kafka.ui.smokeSuite.brokers; - -import com.codeborne.selenide.Condition; -import com.provectus.kafka.ui.BaseTest; -import io.qase.api.annotation.QaseId; -import org.testng.Assert; -import org.testng.annotations.Test; - -import static com.provectus.kafka.ui.pages.brokers.BrokersDetails.DetailsTab.CONFIGS; - -public class BrokersTest extends BaseTest { - - @QaseId(1) - @Test - public void checkBrokersOverview() { - navigateToBrokers(); - Assert.assertTrue(brokersList.getAllBrokers().size() > 0, "getAllBrokers()"); - verifyElementsCondition(brokersList.getAllVisibleElements(), Condition.visible); - verifyElementsCondition(brokersList.getAllEnabledElements(), Condition.enabled); - } - - @QaseId(85) - @Test - public void checkExistingBrokersInCluster() { - navigateToBrokers(); - Assert.assertTrue(brokersList.getAllBrokers().size() > 0, "getAllBrokers()"); - brokersList - .openBroker(1); - brokersDetails - .waitUntilScreenReady(); - verifyElementsCondition(brokersDetails.getAllVisibleElements(), Condition.visible); - verifyElementsCondition(brokersDetails.getAllEnabledElements(), Condition.enabled); - brokersDetails - .openDetailsTab(CONFIGS); - brokersConfigTab - .waitUntilScreenReady(); - verifyElementsCondition(brokersConfigTab.getColumnHeaders(), Condition.visible); - verifyElementsCondition(brokersConfigTab.getEditButtons(), Condition.enabled); - Assert.assertTrue(brokersConfigTab.isSearchByKeyVisible(), "isSearchByKeyVisible()"); - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/connectors/ConnectorsTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/connectors/ConnectorsTest.java deleted file mode 100644 index bdce29e153..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/connectors/ConnectorsTest.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.provectus.kafka.ui.smokeSuite.connectors; - -import com.provectus.kafka.ui.BaseTest; -import com.provectus.kafka.ui.models.Connector; -import com.provectus.kafka.ui.models.Topic; -import io.qase.api.annotation.QaseId; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -import java.util.ArrayList; -import java.util.List; - -import static com.provectus.kafka.ui.pages.BasePage.AlertHeader.SUCCESS; -import static com.provectus.kafka.ui.utilities.FileUtils.getResourceAsString; -import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; - -public class ConnectorsTest extends BaseTest { - - private static final List TOPIC_LIST = new ArrayList<>(); - private static final List CONNECTOR_LIST = new ArrayList<>(); - private static final String MESSAGE_CONTENT = "testData/topics/message_content_create_topic.json"; - private static final String MESSAGE_KEY = " "; - private static final Topic TOPIC_FOR_CREATE = new Topic() - .setName("topic-for-create-connector-" + randomAlphabetic(5)) - .setMessageContent(MESSAGE_CONTENT).setMessageKey(MESSAGE_KEY); - private static final Topic TOPIC_FOR_DELETE = new Topic() - .setName("topic-for-delete-connector-" + randomAlphabetic(5)) - .setMessageContent(MESSAGE_CONTENT).setMessageKey(MESSAGE_KEY); - private static final Topic TOPIC_FOR_UPDATE = new Topic() - .setName("topic-for-update-connector-" + randomAlphabetic(5)) - .setMessageContent(MESSAGE_CONTENT).setMessageKey(MESSAGE_KEY); - private static final Connector CONNECTOR_FOR_DELETE = new Connector() - .setName("connector-for-delete-" + randomAlphabetic(5)) - .setConfig(getResourceAsString("testData/connectors/delete_connector_config.json")); - private static final Connector CONNECTOR_FOR_UPDATE = new Connector() - .setName("connector-for-update-and-delete-" + randomAlphabetic(5)) - .setConfig(getResourceAsString("testData/connectors/config_for_create_connector_via_api.json")); - - @BeforeClass(alwaysRun = true) - public void beforeClass() { - TOPIC_LIST.addAll(List.of(TOPIC_FOR_CREATE, TOPIC_FOR_DELETE, TOPIC_FOR_UPDATE)); - TOPIC_LIST.forEach(topic -> apiService - .createTopic(topic) - .sendMessage(topic) - ); - CONNECTOR_LIST.addAll(List.of(CONNECTOR_FOR_DELETE, CONNECTOR_FOR_UPDATE)); - CONNECTOR_LIST.forEach(connector -> apiService.createConnector(connector)); - } - - @QaseId(42) - @Test - public void createConnector() { - Connector connectorForCreate = new Connector() - .setName("connector-for-create-" + randomAlphabetic(5)) - .setConfig(getResourceAsString("testData/connectors/config_for_create_connector.json")); - navigateToConnectors(); - kafkaConnectList - .clickCreateConnectorBtn(); - connectorCreateForm - .waitUntilScreenReady() - .setConnectorDetails(connectorForCreate.getName(), connectorForCreate.getConfig()) - .clickSubmitButton(); - connectorDetails - .waitUntilScreenReady(); - navigateToConnectorsAndOpenDetails(connectorForCreate.getName()); - Assert.assertTrue(connectorDetails.isConnectorHeaderVisible(connectorForCreate.getName()), "isConnectorTitleVisible()"); - navigateToConnectors(); - Assert.assertTrue(kafkaConnectList.isConnectorVisible(CONNECTOR_FOR_DELETE.getName()), "isConnectorVisible()"); - CONNECTOR_LIST.add(connectorForCreate); - } - - @QaseId(196) - @Test - public void updateConnector() { - navigateToConnectorsAndOpenDetails(CONNECTOR_FOR_UPDATE.getName()); - connectorDetails - .openConfigTab() - .setConfig(CONNECTOR_FOR_UPDATE.getConfig()) - .clickSubmitButton(); - Assert.assertTrue(connectorDetails.isAlertWithMessageVisible(SUCCESS, "Config successfully updated."), "isAlertWithMessageVisible()"); - navigateToConnectors(); - Assert.assertTrue(kafkaConnectList.isConnectorVisible(CONNECTOR_FOR_UPDATE.getName()), "isConnectorVisible()"); - } - - @QaseId(195) - @Test - public void deleteConnector() { - navigateToConnectorsAndOpenDetails(CONNECTOR_FOR_DELETE.getName()); - connectorDetails - .openDotMenu() - .clickDeleteBtn() - .clickConfirmBtn(); - navigateToConnectors(); - Assert.assertFalse(kafkaConnectList.isConnectorVisible(CONNECTOR_FOR_DELETE.getName()), "isConnectorVisible()"); - CONNECTOR_LIST.remove(CONNECTOR_FOR_DELETE); - } - - @AfterClass(alwaysRun = true) - public void afterClass() { - CONNECTOR_LIST.forEach(connector -> - apiService.deleteConnector(connector.getName())); - TOPIC_LIST.forEach(topic -> apiService.deleteTopic(topic.getName())); - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/ksqlDb/KsqlDbTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/ksqlDb/KsqlDbTest.java deleted file mode 100644 index ab1705922a..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/ksqlDb/KsqlDbTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.provectus.kafka.ui.smokeSuite.ksqlDb; - -import com.provectus.kafka.ui.BaseTest; -import com.provectus.kafka.ui.pages.ksqlDb.models.Stream; -import com.provectus.kafka.ui.pages.ksqlDb.models.Table; -import io.qase.api.annotation.QaseId; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import org.testng.asserts.SoftAssert; - -import static com.provectus.kafka.ui.pages.ksqlDb.enums.KsqlQueryConfig.SHOW_TABLES; -import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; - -public class KsqlDbTest extends BaseTest { - - private static final Stream STREAM_FOR_CHECK_TABLES = new Stream() - .setName("STREAM_FOR_CHECK_TABLES_" + randomAlphabetic(4).toUpperCase()) - .setTopicName("TOPIC_FOR_STREAM_" + randomAlphabetic(4).toUpperCase()); - private static final Table FIRST_TABLE = new Table() - .setName("FIRST_TABLE" + randomAlphabetic(4).toUpperCase()) - .setStreamName(STREAM_FOR_CHECK_TABLES.getName()); - private static final Table SECOND_TABLE = new Table() - .setName("SECOND_TABLE" + randomAlphabetic(4).toUpperCase()) - .setStreamName(STREAM_FOR_CHECK_TABLES.getName()); - - @BeforeClass(alwaysRun = true) - public void beforeClass() { - apiService - .createStream(STREAM_FOR_CHECK_TABLES) - .createTables(FIRST_TABLE, SECOND_TABLE); - } - - @QaseId(41) - @Test(priority = 1) - public void checkShowTablesRequestExecution() { - navigateToKsqlDb(); - ksqlDbList - .clickExecuteKsqlRequestBtn(); - ksqlQueryForm - .waitUntilScreenReady() - .setQuery(SHOW_TABLES.getQuery()) - .clickExecuteBtn(); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(ksqlQueryForm.areResultsVisible(), "areResultsVisible()"); - softly.assertTrue(ksqlQueryForm.getTableByName(FIRST_TABLE.getName()).isVisible(), "getTableName()"); - softly.assertTrue(ksqlQueryForm.getTableByName(SECOND_TABLE.getName()).isVisible(), "getTableName()"); - softly.assertAll(); - } - - @QaseId(86) - @Test(priority = 2) - public void clearResultsForExecutedRequest() { - navigateToKsqlDb(); - ksqlDbList - .clickExecuteKsqlRequestBtn(); - ksqlQueryForm - .waitUntilScreenReady() - .setQuery(SHOW_TABLES.getQuery()) - .clickExecuteBtn(); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(ksqlQueryForm.areResultsVisible(), "areResultsVisible()"); - softly.assertAll(); - ksqlQueryForm - .clickClearResultsBtn(); - softly.assertFalse(ksqlQueryForm.areResultsVisible(), "areResultsVisible()"); - softly.assertAll(); - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/schemas/SchemasTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/schemas/SchemasTest.java deleted file mode 100644 index 9b2a1618c2..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/schemas/SchemasTest.java +++ /dev/null @@ -1,190 +0,0 @@ -package com.provectus.kafka.ui.smokeSuite.schemas; - -import com.codeborne.selenide.Condition; -import com.provectus.kafka.ui.BaseTest; -import com.provectus.kafka.ui.api.model.CompatibilityLevel; -import com.provectus.kafka.ui.models.Schema; -import io.qase.api.annotation.QaseId; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import org.testng.asserts.SoftAssert; - -import java.util.ArrayList; -import java.util.List; - -import static com.provectus.kafka.ui.utilities.FileUtils.fileToString; - -public class SchemasTest extends BaseTest { - - private static final List SCHEMA_LIST = new ArrayList<>(); - private static final Schema AVRO_API = Schema.createSchemaAvro(); - private static final Schema JSON_API = Schema.createSchemaJson(); - private static final Schema PROTOBUF_API = Schema.createSchemaProtobuf(); - - @BeforeClass(alwaysRun = true) - public void beforeClass() { - SCHEMA_LIST.addAll(List.of(AVRO_API, JSON_API, PROTOBUF_API)); - SCHEMA_LIST.forEach(schema -> apiService.createSchema(schema)); - } - - @QaseId(43) - @Test(priority = 1) - public void createSchemaAvro() { - Schema schemaAvro = Schema.createSchemaAvro(); - navigateToSchemaRegistry(); - schemaRegistryList - .clickCreateSchema(); - schemaCreateForm - .setSubjectName(schemaAvro.getName()) - .setSchemaField(fileToString(schemaAvro.getValuePath())) - .selectSchemaTypeFromDropdown(schemaAvro.getType()) - .clickSubmitButton(); - schemaDetails - .waitUntilScreenReady(); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(schemaDetails.isSchemaHeaderVisible(schemaAvro.getName()), "isSchemaHeaderVisible()"); - softly.assertEquals(schemaDetails.getSchemaType(), schemaAvro.getType().getValue(), "getSchemaType()"); - softly.assertEquals(schemaDetails.getCompatibility(), CompatibilityLevel.CompatibilityEnum.BACKWARD.getValue(), - "getCompatibility()"); - softly.assertAll(); - navigateToSchemaRegistry(); - Assert.assertTrue(schemaRegistryList.isSchemaVisible(AVRO_API.getName()), "isSchemaVisible()"); - SCHEMA_LIST.add(schemaAvro); - } - - @QaseId(186) - @Test(priority = 2) - public void updateSchemaAvro() { - AVRO_API.setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_avro_for_update.json"); - navigateToSchemaRegistryAndOpenDetails(AVRO_API.getName()); - schemaDetails - .openEditSchema(); - schemaCreateForm - .waitUntilScreenReady(); - verifyElementsCondition(schemaCreateForm.getAllDetailsPageElements(), Condition.visible); - SoftAssert softly = new SoftAssert(); - softly.assertFalse(schemaCreateForm.isSubmitBtnEnabled(), "isSubmitBtnEnabled()"); - softly.assertFalse(schemaCreateForm.isSchemaDropDownEnabled(), "isSchemaDropDownEnabled()"); - softly.assertAll(); - schemaCreateForm - .selectCompatibilityLevelFromDropdown(CompatibilityLevel.CompatibilityEnum.NONE) - .setNewSchemaValue(fileToString(AVRO_API.getValuePath())) - .clickSubmitButton(); - schemaDetails - .waitUntilScreenReady(); - Assert.assertEquals(schemaDetails.getCompatibility(), CompatibilityLevel.CompatibilityEnum.NONE.toString(), - "getCompatibility()"); - } - - @QaseId(44) - @Test(priority = 3) - public void compareVersionsOperation() { - navigateToSchemaRegistryAndOpenDetails(AVRO_API.getName()); - int latestVersion = schemaDetails - .waitUntilScreenReady() - .getLatestVersion(); - schemaDetails - .openCompareVersionMenu(); - int versionsNumberFromDdl = schemaCreateForm - .waitUntilScreenReady() - .openLeftVersionDdl() - .getVersionsNumberFromList(); - Assert.assertEquals(versionsNumberFromDdl, latestVersion, "Versions number is not matched"); - schemaCreateForm - .selectVersionFromDropDown(1); - Assert.assertEquals(schemaCreateForm.getMarkedLinesNumber(), 42, "getAllMarkedLines()"); - } - - @QaseId(187) - @Test(priority = 4) - public void deleteSchemaAvro() { - navigateToSchemaRegistryAndOpenDetails(AVRO_API.getName()); - schemaDetails - .removeSchema(); - schemaRegistryList - .waitUntilScreenReady(); - Assert.assertFalse(schemaRegistryList.isSchemaVisible(AVRO_API.getName()), "isSchemaVisible()"); - SCHEMA_LIST.remove(AVRO_API); - } - - @QaseId(89) - @Test(priority = 5) - public void createSchemaJson() { - Schema schemaJson = Schema.createSchemaJson(); - navigateToSchemaRegistry(); - schemaRegistryList - .clickCreateSchema(); - schemaCreateForm - .setSubjectName(schemaJson.getName()) - .setSchemaField(fileToString(schemaJson.getValuePath())) - .selectSchemaTypeFromDropdown(schemaJson.getType()) - .clickSubmitButton(); - schemaDetails - .waitUntilScreenReady(); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(schemaDetails.isSchemaHeaderVisible(schemaJson.getName()), "isSchemaHeaderVisible()"); - softly.assertEquals(schemaDetails.getSchemaType(), schemaJson.getType().getValue(), "getSchemaType()"); - softly.assertEquals(schemaDetails.getCompatibility(), CompatibilityLevel.CompatibilityEnum.BACKWARD.getValue(), - "getCompatibility()"); - softly.assertAll(); - navigateToSchemaRegistry(); - Assert.assertTrue(schemaRegistryList.isSchemaVisible(JSON_API.getName()), "isSchemaVisible()"); - SCHEMA_LIST.add(schemaJson); - } - - @QaseId(189) - @Test(priority = 6) - public void deleteSchemaJson() { - navigateToSchemaRegistryAndOpenDetails(JSON_API.getName()); - schemaDetails - .removeSchema(); - schemaRegistryList - .waitUntilScreenReady(); - Assert.assertFalse(schemaRegistryList.isSchemaVisible(JSON_API.getName()), "isSchemaVisible()"); - SCHEMA_LIST.remove(JSON_API); - } - - @QaseId(91) - @Test(priority = 7) - public void createSchemaProtobuf() { - Schema schemaProtobuf = Schema.createSchemaProtobuf(); - navigateToSchemaRegistry(); - schemaRegistryList - .clickCreateSchema(); - schemaCreateForm - .setSubjectName(schemaProtobuf.getName()) - .setSchemaField(fileToString(schemaProtobuf.getValuePath())) - .selectSchemaTypeFromDropdown(schemaProtobuf.getType()) - .clickSubmitButton(); - schemaDetails - .waitUntilScreenReady(); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(schemaDetails.isSchemaHeaderVisible(schemaProtobuf.getName()), "isSchemaHeaderVisible()"); - softly.assertEquals(schemaDetails.getSchemaType(), schemaProtobuf.getType().getValue(), "getSchemaType()"); - softly.assertEquals(schemaDetails.getCompatibility(), CompatibilityLevel.CompatibilityEnum.BACKWARD.getValue(), - "getCompatibility()"); - softly.assertAll(); - navigateToSchemaRegistry(); - Assert.assertTrue(schemaRegistryList.isSchemaVisible(PROTOBUF_API.getName()), "isSchemaVisible()"); - SCHEMA_LIST.add(schemaProtobuf); - } - - @QaseId(223) - @Test(priority = 8) - public void deleteSchemaProtobuf() { - navigateToSchemaRegistryAndOpenDetails(PROTOBUF_API.getName()); - schemaDetails - .removeSchema(); - schemaRegistryList - .waitUntilScreenReady(); - Assert.assertFalse(schemaRegistryList.isSchemaVisible(PROTOBUF_API.getName()), "isSchemaVisible()"); - SCHEMA_LIST.remove(PROTOBUF_API); - } - - @AfterClass(alwaysRun = true) - public void afterClass() { - SCHEMA_LIST.forEach(schema -> apiService.deleteSchema(schema.getName())); - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/topics/MessagesTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/topics/MessagesTest.java deleted file mode 100644 index 00a0413e7d..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/topics/MessagesTest.java +++ /dev/null @@ -1,283 +0,0 @@ -package com.provectus.kafka.ui.smokeSuite.topics; - -import com.provectus.kafka.ui.BaseTest; -import com.provectus.kafka.ui.models.Topic; -import com.provectus.kafka.ui.pages.topics.TopicDetails; -import io.qameta.allure.Issue; -import io.qameta.allure.Step; -import io.qase.api.annotation.QaseId; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Ignore; -import org.testng.annotations.Test; -import org.testng.asserts.SoftAssert; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.stream.IntStream; - -import static com.provectus.kafka.ui.pages.BasePage.AlertHeader.SUCCESS; -import static com.provectus.kafka.ui.pages.topics.TopicDetails.TopicMenu.MESSAGES; -import static com.provectus.kafka.ui.pages.topics.TopicDetails.TopicMenu.OVERVIEW; -import static com.provectus.kafka.ui.utilities.TimeUtils.waitUntilNewMinuteStarted; -import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; - -public class MessagesTest extends BaseTest { - - private static final Topic TOPIC_FOR_MESSAGES = new Topic() - .setName("topic-with-clean-message-attribute-" + randomAlphabetic(5)) - .setMessageKey(randomAlphabetic(5)) - .setMessageContent(randomAlphabetic(10)); - private static final Topic TOPIC_TO_CLEAR_AND_PURGE_MESSAGES = new Topic() - .setName("topic-to-clear-and-purge-messages-" + randomAlphabetic(5)) - .setMessageKey(randomAlphabetic(5)) - .setMessageContent(randomAlphabetic(10)); - private static final Topic TOPIC_FOR_CHECK_FILTERS = new Topic() - .setName("topic-for-check-filters-" + randomAlphabetic(5)) - .setMessageKey(randomAlphabetic(5)) - .setMessageContent(randomAlphabetic(10)); - private static final Topic TOPIC_TO_RECREATE = new Topic() - .setName("topic-to-recreate-attribute-" + randomAlphabetic(5)) - .setMessageKey(randomAlphabetic(5)) - .setMessageContent(randomAlphabetic(10)); - private static final Topic TOPIC_FOR_CHECK_MESSAGES_COUNT = new Topic() - .setName("topic-for-check-messages-count" + randomAlphabetic(5)) - .setMessageKey(randomAlphabetic(5)) - .setMessageContent(randomAlphabetic(10)); - private static final List TOPIC_LIST = new ArrayList<>(); - - @BeforeClass(alwaysRun = true) - public void beforeClass() { - TOPIC_LIST.addAll(List.of(TOPIC_FOR_MESSAGES, TOPIC_FOR_CHECK_FILTERS, TOPIC_TO_CLEAR_AND_PURGE_MESSAGES, - TOPIC_TO_RECREATE, TOPIC_FOR_CHECK_MESSAGES_COUNT)); - TOPIC_LIST.forEach(topic -> apiService.createTopic(topic)); - IntStream.range(1, 3).forEach(i -> apiService.sendMessage(TOPIC_FOR_CHECK_FILTERS)); - waitUntilNewMinuteStarted(); - IntStream.range(1, 3).forEach(i -> apiService.sendMessage(TOPIC_FOR_CHECK_FILTERS)); - IntStream.range(1, 110).forEach(i -> apiService.sendMessage(TOPIC_FOR_CHECK_MESSAGES_COUNT)); - } - - @QaseId(222) - @Test(priority = 1) - public void produceMessage() { - navigateToTopicsAndOpenDetails(TOPIC_FOR_MESSAGES.getName()); - topicDetails - .openDetailsTab(MESSAGES); - produceMessage(TOPIC_FOR_MESSAGES); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(topicDetails.isKeyMessageVisible((TOPIC_FOR_MESSAGES.getMessageKey())), - "isKeyMessageVisible()"); - softly.assertTrue(topicDetails.isContentMessageVisible((TOPIC_FOR_MESSAGES.getMessageContent()).trim()), - "isContentMessageVisible()"); - softly.assertAll(); - } - - @QaseId(19) - @Test(priority = 2) - public void clearMessage() { - navigateToTopicsAndOpenDetails(TOPIC_FOR_MESSAGES.getName()); - topicDetails - .openDetailsTab(OVERVIEW); - int messageAmount = topicDetails.getMessageCountAmount(); - produceMessage(TOPIC_FOR_MESSAGES); - Assert.assertEquals(topicDetails.getMessageCountAmount(), messageAmount + 1, "getMessageCountAmount()"); - topicDetails - .openDotMenu() - .clickClearMessagesMenu() - .clickConfirmBtnMdl() - .waitUntilScreenReady(); - Assert.assertEquals(topicDetails.getMessageCountAmount(), 0, "getMessageCountAmount()"); - } - - @QaseId(239) - @Test(priority = 3) - public void checkClearTopicMessage() { - navigateToTopicsAndOpenDetails(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()); - topicDetails - .openDetailsTab(OVERVIEW); - produceMessage(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES); - navigateToTopics(); - Assert.assertEquals(topicsList.getTopicItem(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()).getNumberOfMessages(), 1, - "getNumberOfMessages()"); - topicsList - .openDotMenuByTopicName(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()) - .clickClearMessagesBtn() - .clickConfirmBtnMdl(); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(topicsList.isAlertWithMessageVisible(SUCCESS, - String.format("%s messages have been successfully cleared!", TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName())), - "isAlertWithMessageVisible()"); - softly.assertEquals(topicsList.getTopicItem(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()).getNumberOfMessages(), 0, - "getNumberOfMessages()"); - softly.assertAll(); - } - - @QaseId(10) - @Test(priority = 4) - public void checkPurgeMessagePossibility() { - navigateToTopics(); - int messageAmount = topicsList.getTopicItem(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()).getNumberOfMessages(); - topicsList - .openTopic(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()); - topicDetails - .openDetailsTab(OVERVIEW); - produceMessage(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES); - navigateToTopics(); - Assert.assertEquals(topicsList.getTopicItem(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()).getNumberOfMessages(), - messageAmount + 1, "getNumberOfMessages()"); - topicsList - .getTopicItem(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()) - .selectItem(true) - .clickPurgeMessagesOfSelectedTopicsBtn(); - Assert.assertTrue(topicsList.isConfirmationMdlVisible(), "isConfirmationMdlVisible()"); - topicsList - .clickCancelBtnMdl() - .clickPurgeMessagesOfSelectedTopicsBtn() - .clickConfirmBtnMdl(); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(topicsList.isAlertWithMessageVisible(SUCCESS, - String.format("%s messages have been successfully cleared!", TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName())), - "isAlertWithMessageVisible()"); - softly.assertEquals(topicsList.getTopicItem(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()).getNumberOfMessages(), 0, - "getNumberOfMessages()"); - softly.assertAll(); - } - - @Ignore - @Issue("https://github.com/provectus/kafka-ui/issues/2394") - @QaseId(15) - @Test(priority = 6) - public void checkMessageFilteringByOffset() { - navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_FILTERS.getName()); - topicDetails - .openDetailsTab(MESSAGES); - TopicDetails.MessageGridItem secondMessage = topicDetails.getMessageByOffset(1); - topicDetails - .selectSeekTypeDdlMessagesTab("Offset") - .setSeekTypeValueFldMessagesTab(String.valueOf(secondMessage.getOffset())) - .clickSubmitFiltersBtnMessagesTab(); - SoftAssert softly = new SoftAssert(); - topicDetails.getAllMessages().forEach(message -> - softly.assertTrue(message.getOffset() == secondMessage.getOffset() - || message.getOffset() > secondMessage.getOffset(), - String.format("Expected offset is: %s, but found: %s", secondMessage.getOffset(), message.getOffset()))); - softly.assertAll(); - } - - @Ignore - @Issue("https://github.com/provectus/kafka-ui/issues/3215") - @Issue("https://github.com/provectus/kafka-ui/issues/2345") - @QaseId(16) - @Test(priority = 7) - public void checkMessageFilteringByTimestamp() { - navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_FILTERS.getName()); - topicDetails - .openDetailsTab(MESSAGES); - LocalDateTime firstTimestamp = topicDetails.getMessageByOffset(0).getTimestamp(); - List nextMessages = topicDetails.getAllMessages().stream() - .filter(message -> message.getTimestamp().getMinute() != firstTimestamp.getMinute()) - .toList(); - LocalDateTime nextTimestamp = Objects.requireNonNull(nextMessages.stream() - .findFirst().orElseThrow()).getTimestamp(); - topicDetails - .selectSeekTypeDdlMessagesTab("Timestamp") - .openCalendarSeekType() - .selectDateAndTimeByCalendar(nextTimestamp) - .clickSubmitFiltersBtnMessagesTab(); - SoftAssert softly = new SoftAssert(); - topicDetails.getAllMessages().forEach(message -> - softly.assertTrue(message.getTimestamp().isEqual(nextTimestamp) - || message.getTimestamp().isAfter(nextTimestamp), - String.format("Expected timestamp is: %s, but found: %s", nextTimestamp, message.getTimestamp()))); - softly.assertAll(); - } - - @Ignore - @Issue("https://github.com/provectus/kafka-ui/issues/2778") - @QaseId(246) - @Test(priority = 8) - public void checkClearTopicMessageFromOverviewTab() { - navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_FILTERS.getName()); - topicDetails - .openDetailsTab(OVERVIEW) - .openDotMenu() - .clickClearMessagesMenu() - .clickConfirmBtnMdl(); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(topicDetails.isAlertWithMessageVisible(SUCCESS, - String.format("%s messages have been successfully cleared!", TOPIC_FOR_CHECK_FILTERS.getName())), - "isAlertWithMessageVisible()"); - softly.assertEquals(topicDetails.getMessageCountAmount(), 0, - "getMessageCountAmount()= " + topicDetails.getMessageCountAmount()); - softly.assertAll(); - } - - @QaseId(240) - @Test(priority = 9) - public void checkRecreateTopic() { - navigateToTopicsAndOpenDetails(TOPIC_TO_RECREATE.getName()); - topicDetails - .openDetailsTab(OVERVIEW); - produceMessage(TOPIC_TO_RECREATE); - navigateToTopics(); - Assert.assertEquals(topicsList.getTopicItem(TOPIC_TO_RECREATE.getName()).getNumberOfMessages(), 1, - "getNumberOfMessages()"); - topicsList - .openDotMenuByTopicName(TOPIC_TO_RECREATE.getName()) - .clickRecreateTopicBtn() - .clickConfirmBtnMdl(); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(topicDetails.isAlertWithMessageVisible(SUCCESS, - String.format("Topic %s successfully recreated!", TOPIC_TO_RECREATE.getName())), - "isAlertWithMessageVisible()"); - softly.assertEquals(topicsList.getTopicItem(TOPIC_TO_RECREATE.getName()).getNumberOfMessages(), 0, - "getNumberOfMessages()"); - softly.assertAll(); - } - - @Ignore - @Issue("https://github.com/provectus/kafka-ui/issues/3129") - @QaseId(267) - @Test(priority = 10) - public void CheckMessagesCountPerPageWithinTopic() { - navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_MESSAGES_COUNT.getName()); - topicDetails - .openDetailsTab(MESSAGES); - int messagesPerPage = topicDetails.getAllMessages().size(); - SoftAssert softly = new SoftAssert(); - softly.assertEquals(messagesPerPage, 100, "getAllMessages()"); - softly.assertFalse(topicDetails.isBackButtonEnabled(), "isBackButtonEnabled()"); - softly.assertTrue(topicDetails.isNextButtonEnabled(), "isNextButtonEnabled()"); - softly.assertAll(); - int lastOffsetOnPage = topicDetails.getAllMessages() - .get(messagesPerPage - 1).getOffset(); - topicDetails - .clickNextButton(); - softly.assertEquals(topicDetails.getAllMessages().stream().findFirst().orElseThrow().getOffset(), - lastOffsetOnPage + 1, "findFirst().getOffset()"); - softly.assertTrue(topicDetails.isBackButtonEnabled(), "isBackButtonEnabled()"); - softly.assertFalse(topicDetails.isNextButtonEnabled(), "isNextButtonEnabled()"); - softly.assertAll(); - } - - @Step - protected void produceMessage(Topic topic) { - topicDetails - .clickProduceMessageBtn(); - produceMessagePanel - .waitUntilScreenReady() - .setKeyField(topic.getMessageKey()) - .setContentFiled(topic.getMessageContent()) - .submitProduceMessage(); - topicDetails - .waitUntilScreenReady(); - } - - @AfterClass(alwaysRun = true) - public void afterClass() { - TOPIC_LIST.forEach(topic -> apiService.deleteTopic(topic.getName())); - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/topics/TopicsTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/topics/TopicsTest.java deleted file mode 100644 index 8cca35beb6..0000000000 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/topics/TopicsTest.java +++ /dev/null @@ -1,497 +0,0 @@ -package com.provectus.kafka.ui.smokeSuite.topics; - -import com.codeborne.selenide.Condition; -import com.provectus.kafka.ui.BaseTest; -import com.provectus.kafka.ui.models.Topic; -import com.provectus.kafka.ui.pages.topics.TopicDetails; -import io.qameta.allure.Issue; -import io.qase.api.annotation.QaseId; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Ignore; -import org.testng.annotations.Test; -import org.testng.asserts.SoftAssert; - -import java.util.ArrayList; -import java.util.List; - -import static com.provectus.kafka.ui.pages.BasePage.AlertHeader.SUCCESS; -import static com.provectus.kafka.ui.pages.topics.TopicDetails.TopicMenu.MESSAGES; -import static com.provectus.kafka.ui.pages.topics.TopicDetails.TopicMenu.SETTINGS; -import static com.provectus.kafka.ui.pages.topics.enums.CleanupPolicyValue.COMPACT; -import static com.provectus.kafka.ui.pages.topics.enums.CleanupPolicyValue.DELETE; -import static com.provectus.kafka.ui.pages.topics.enums.CustomParameterType.COMPRESSION_TYPE; -import static com.provectus.kafka.ui.pages.topics.enums.MaxSizeOnDisk.*; -import static com.provectus.kafka.ui.pages.topics.enums.TimeToRetain.BTN_2_DAYS; -import static com.provectus.kafka.ui.pages.topics.enums.TimeToRetain.BTN_7_DAYS; -import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; -import static org.apache.commons.lang3.RandomUtils.nextInt; - -public class TopicsTest extends BaseTest { - - private static final Topic TOPIC_TO_CREATE = new Topic() - .setName("new-topic-" + randomAlphabetic(5)) - .setNumberOfPartitions(1) - .setCustomParameterType(COMPRESSION_TYPE) - .setCustomParameterValue("producer") - .setCleanupPolicyValue(DELETE); - private static final Topic TOPIC_TO_UPDATE_AND_DELETE = new Topic() - .setName("topic-to-update-and-delete-" + randomAlphabetic(5)) - .setNumberOfPartitions(1) - .setCleanupPolicyValue(DELETE) - .setTimeToRetain(BTN_7_DAYS) - .setMaxSizeOnDisk(NOT_SET) - .setMaxMessageBytes("1048588") - .setMessageKey(randomAlphabetic(5)) - .setMessageContent(randomAlphabetic(10)); - private static final Topic TOPIC_TO_CHECK_SETTINGS = new Topic() - .setName("new-topic-" + randomAlphabetic(5)) - .setNumberOfPartitions(1) - .setMaxMessageBytes("1000012") - .setMaxSizeOnDisk(NOT_SET); - private static final Topic TOPIC_FOR_CHECK_FILTERS = new Topic() - .setName("topic-for-check-filters-" + randomAlphabetic(5)); - private static final Topic TOPIC_FOR_DELETE = new Topic() - .setName("topic-to-delete-" + randomAlphabetic(5)); - private static final List TOPIC_LIST = new ArrayList<>(); - - @BeforeClass(alwaysRun = true) - public void beforeClass() { - TOPIC_LIST.addAll(List.of(TOPIC_TO_UPDATE_AND_DELETE, TOPIC_FOR_DELETE, TOPIC_FOR_CHECK_FILTERS)); - TOPIC_LIST.forEach(topic -> apiService.createTopic(topic)); - } - - @QaseId(199) - @Test(priority = 1) - public void createTopic() { - navigateToTopics(); - topicsList - .clickAddTopicBtn(); - topicCreateEditForm - .waitUntilScreenReady() - .setTopicName(TOPIC_TO_CREATE.getName()) - .setNumberOfPartitions(TOPIC_TO_CREATE.getNumberOfPartitions()) - .selectCleanupPolicy(TOPIC_TO_CREATE.getCleanupPolicyValue()) - .clickCreateTopicBtn(); - navigateToTopicsAndOpenDetails(TOPIC_TO_CREATE.getName()); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(topicDetails.isTopicHeaderVisible(TOPIC_TO_CREATE.getName()), "isTopicHeaderVisible()"); - softly.assertEquals(topicDetails.getCleanUpPolicy(), TOPIC_TO_CREATE.getCleanupPolicyValue().toString(), "getCleanUpPolicy()"); - softly.assertEquals(topicDetails.getPartitions(), TOPIC_TO_CREATE.getNumberOfPartitions(), "getPartitions()"); - softly.assertAll(); - navigateToTopics(); - Assert.assertTrue(topicsList.isTopicVisible(TOPIC_TO_CREATE.getName()), "isTopicVisible()"); - TOPIC_LIST.add(TOPIC_TO_CREATE); - } - - @QaseId(7) - @Test(priority = 2) - void checkAvailableOperations() { - navigateToTopics(); - topicsList - .getTopicItem(TOPIC_TO_UPDATE_AND_DELETE.getName()) - .selectItem(true); - verifyElementsCondition(topicsList.getActionButtons(), Condition.enabled); - topicsList - .getTopicItem(TOPIC_FOR_CHECK_FILTERS.getName()) - .selectItem(true); - Assert.assertFalse(topicsList.isCopySelectedTopicBtnEnabled(), "isCopySelectedTopicBtnEnabled()"); - } - - @Ignore - @Issue("https://github.com/provectus/kafka-ui/issues/3071") - @QaseId(268) - @Test(priority = 3) - public void checkCustomParametersWithinEditExistingTopic() { - navigateToTopicsAndOpenDetails(TOPIC_TO_UPDATE_AND_DELETE.getName()); - topicDetails - .openDotMenu() - .clickEditSettingsMenu(); - SoftAssert softly = new SoftAssert(); - topicCreateEditForm - .waitUntilScreenReady() - .clickAddCustomParameterTypeButton() - .openCustomParameterTypeDdl() - .getAllDdlOptions() - .forEach(option -> - softly.assertTrue(!option.is(Condition.attribute("disabled")), - option.getText() + " is enabled:")); - softly.assertAll(); - } - - @QaseId(197) - @Test(priority = 4) - public void updateTopic() { - navigateToTopicsAndOpenDetails(TOPIC_TO_UPDATE_AND_DELETE.getName()); - topicDetails - .openDotMenu() - .clickEditSettingsMenu(); - topicCreateEditForm - .waitUntilScreenReady(); - SoftAssert softly = new SoftAssert(); - softly.assertEquals(topicCreateEditForm.getCleanupPolicy(), - TOPIC_TO_UPDATE_AND_DELETE.getCleanupPolicyValue().getVisibleText(), "getCleanupPolicy()"); - softly.assertEquals(topicCreateEditForm.getTimeToRetain(), - TOPIC_TO_UPDATE_AND_DELETE.getTimeToRetain().getValue(), "getTimeToRetain()"); - softly.assertEquals(topicCreateEditForm.getMaxSizeOnDisk(), - TOPIC_TO_UPDATE_AND_DELETE.getMaxSizeOnDisk().getVisibleText(), "getMaxSizeOnDisk()"); - softly.assertEquals(topicCreateEditForm.getMaxMessageBytes(), - TOPIC_TO_UPDATE_AND_DELETE.getMaxMessageBytes(), "getMaxMessageBytes()"); - softly.assertAll(); - TOPIC_TO_UPDATE_AND_DELETE - .setCleanupPolicyValue(COMPACT) - .setTimeToRetain(BTN_2_DAYS) - .setMaxSizeOnDisk(SIZE_50_GB).setMaxMessageBytes("1048589"); - topicCreateEditForm - .selectCleanupPolicy((TOPIC_TO_UPDATE_AND_DELETE.getCleanupPolicyValue())) - .setTimeToRetainDataByButtons(TOPIC_TO_UPDATE_AND_DELETE.getTimeToRetain()) - .setMaxSizeOnDiskInGB(TOPIC_TO_UPDATE_AND_DELETE.getMaxSizeOnDisk()) - .setMaxMessageBytes(TOPIC_TO_UPDATE_AND_DELETE.getMaxMessageBytes()) - .clickCreateTopicBtn(); - softly.assertTrue(topicDetails.isAlertWithMessageVisible(SUCCESS, "Topic successfully updated."), - "isAlertWithMessageVisible()"); - softly.assertTrue(topicDetails.isTopicHeaderVisible(TOPIC_TO_UPDATE_AND_DELETE.getName()), - "isTopicHeaderVisible()"); - softly.assertAll(); - topicDetails - .waitUntilScreenReady(); - navigateToTopicsAndOpenDetails(TOPIC_TO_UPDATE_AND_DELETE.getName()); - topicDetails - .openDotMenu() - .clickEditSettingsMenu(); - softly.assertFalse(topicCreateEditForm.isNameFieldEnabled(), "isNameFieldEnabled()"); - softly.assertEquals(topicCreateEditForm.getCleanupPolicy(), - TOPIC_TO_UPDATE_AND_DELETE.getCleanupPolicyValue().getVisibleText(), "getCleanupPolicy()"); - softly.assertEquals(topicCreateEditForm.getTimeToRetain(), - TOPIC_TO_UPDATE_AND_DELETE.getTimeToRetain().getValue(), "getTimeToRetain()"); - softly.assertEquals(topicCreateEditForm.getMaxSizeOnDisk(), - TOPIC_TO_UPDATE_AND_DELETE.getMaxSizeOnDisk().getVisibleText(), "getMaxSizeOnDisk()"); - softly.assertEquals(topicCreateEditForm.getMaxMessageBytes(), - TOPIC_TO_UPDATE_AND_DELETE.getMaxMessageBytes(), "getMaxMessageBytes()"); - softly.assertAll(); - } - - @QaseId(242) - @Test(priority = 5) - public void removeTopicFromTopicList() { - navigateToTopics(); - topicsList - .openDotMenuByTopicName(TOPIC_TO_UPDATE_AND_DELETE.getName()) - .clickRemoveTopicBtn() - .clickConfirmBtnMdl(); - Assert.assertTrue(topicsList.isAlertWithMessageVisible(SUCCESS, - String.format("Topic %s successfully deleted!", TOPIC_TO_UPDATE_AND_DELETE.getName())), - "isAlertWithMessageVisible()"); - TOPIC_LIST.remove(TOPIC_TO_UPDATE_AND_DELETE); - } - - @QaseId(207) - @Test(priority = 6) - public void deleteTopic() { - navigateToTopicsAndOpenDetails(TOPIC_FOR_DELETE.getName()); - topicDetails - .openDotMenu() - .clickDeleteTopicMenu() - .clickConfirmBtnMdl(); - navigateToTopics(); - Assert.assertFalse(topicsList.isTopicVisible(TOPIC_FOR_DELETE.getName()), "isTopicVisible"); - TOPIC_LIST.remove(TOPIC_FOR_DELETE); - } - - @QaseId(20) - @Test(priority = 7) - public void redirectToConsumerFromTopic() { - String topicName = "source-activities"; - String consumerGroupId = "connect-sink_postgres_activities"; - navigateToTopicsAndOpenDetails(topicName); - topicDetails - .openDetailsTab(TopicDetails.TopicMenu.CONSUMERS) - .openConsumerGroup(consumerGroupId); - consumersDetails - .waitUntilScreenReady(); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(consumersDetails.isRedirectedConsumerTitleVisible(consumerGroupId), - "isRedirectedConsumerTitleVisible()"); - softly.assertTrue(consumersDetails.isTopicInConsumersDetailsVisible(topicName), - "isTopicInConsumersDetailsVisible()"); - softly.assertAll(); - } - - @QaseId(4) - @Test(priority = 8) - public void checkTopicCreatePossibility() { - navigateToTopics(); - topicsList - .clickAddTopicBtn(); - topicCreateEditForm - .waitUntilScreenReady(); - Assert.assertFalse(topicCreateEditForm.isCreateTopicButtonEnabled(), "isCreateTopicButtonEnabled()"); - topicCreateEditForm - .setTopicName("testName"); - Assert.assertFalse(topicCreateEditForm.isCreateTopicButtonEnabled(), "isCreateTopicButtonEnabled()"); - topicCreateEditForm - .setTopicName(null) - .setNumberOfPartitions(nextInt(1, 10)); - Assert.assertFalse(topicCreateEditForm.isCreateTopicButtonEnabled(), "isCreateTopicButtonEnabled()"); - topicCreateEditForm - .setTopicName("testName"); - Assert.assertTrue(topicCreateEditForm.isCreateTopicButtonEnabled(), "isCreateTopicButtonEnabled()"); - } - - @QaseId(266) - @Test(priority = 9) - public void checkTimeToRetainDataCustomValueWithEditingTopic() { - Topic topicToRetainData = new Topic() - .setName("topic-to-retain-data-" + randomAlphabetic(5)) - .setTimeToRetainData("86400000"); - navigateToTopics(); - topicsList - .clickAddTopicBtn(); - topicCreateEditForm - .waitUntilScreenReady() - .setTopicName(topicToRetainData.getName()) - .setNumberOfPartitions(1) - .setTimeToRetainDataInMs("604800000"); - Assert.assertEquals(topicCreateEditForm.getTimeToRetain(), "604800000", "getTimeToRetain()"); - topicCreateEditForm - .setTimeToRetainDataInMs(topicToRetainData.getTimeToRetainData()) - .clickCreateTopicBtn(); - topicDetails - .waitUntilScreenReady() - .openDotMenu() - .clickEditSettingsMenu(); - Assert.assertEquals(topicCreateEditForm.getTimeToRetain(), topicToRetainData.getTimeToRetainData(), - "getTimeToRetain()"); - topicDetails - .openDetailsTab(SETTINGS); - Assert.assertEquals(topicDetails.getSettingsGridValueByKey("retention.ms"), topicToRetainData.getTimeToRetainData(), - "getSettingsGridValueByKey()"); - TOPIC_LIST.add(topicToRetainData); - } - - @QaseId(6) - @Test(priority = 10) - public void checkCustomParametersWithinCreateNewTopic() { - navigateToTopics(); - topicsList - .clickAddTopicBtn(); - topicCreateEditForm - .waitUntilScreenReady() - .setTopicName(TOPIC_TO_CREATE.getName()) - .clickAddCustomParameterTypeButton() - .setCustomParameterType(TOPIC_TO_CREATE.getCustomParameterType()); - Assert.assertTrue(topicCreateEditForm.isDeleteCustomParameterButtonEnabled(), - "isDeleteCustomParameterButtonEnabled()"); - topicCreateEditForm - .clearCustomParameterValue(); - Assert.assertTrue(topicCreateEditForm.isValidationMessageCustomParameterValueVisible(), - "isValidationMessageCustomParameterValueVisible()"); - } - - @QaseId(2) - @Test(priority = 11) - public void checkTopicListElements() { - navigateToTopics(); - verifyElementsCondition(topicsList.getAllVisibleElements(), Condition.visible); - verifyElementsCondition(topicsList.getAllEnabledElements(), Condition.enabled); - } - - @QaseId(12) - @Test(priority = 12) - public void addNewFilterWithinTopic() { - String filterName = randomAlphabetic(5); - navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_FILTERS.getName()); - topicDetails - .openDetailsTab(MESSAGES) - .clickMessagesAddFiltersBtn() - .waitUntilAddFiltersMdlVisible(); - verifyElementsCondition(topicDetails.getAllAddFilterModalVisibleElements(), Condition.visible); - verifyElementsCondition(topicDetails.getAllAddFilterModalEnabledElements(), Condition.enabled); - verifyElementsCondition(topicDetails.getAllAddFilterModalDisabledElements(), Condition.disabled); - Assert.assertFalse(topicDetails.isSaveThisFilterCheckBoxSelected(), "isSaveThisFilterCheckBoxSelected()"); - topicDetails - .setFilterCodeFieldAddFilterMdl(filterName); - Assert.assertTrue(topicDetails.isAddFilterBtnAddFilterMdlEnabled(), "isAddFilterBtnAddFilterMdlEnabled()"); - topicDetails.clickAddFilterBtnAndCloseMdl(true); - Assert.assertTrue(topicDetails.isActiveFilterVisible(filterName), "isActiveFilterVisible()"); - } - - @QaseId(13) - @Test(priority = 13) - public void checkFilterSavingWithinSavedFilters() { - String displayName = randomAlphabetic(5); - navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_FILTERS.getName()); - topicDetails - .openDetailsTab(MESSAGES) - .clickMessagesAddFiltersBtn() - .waitUntilAddFiltersMdlVisible() - .setFilterCodeFieldAddFilterMdl(randomAlphabetic(4)) - .selectSaveThisFilterCheckboxMdl(true) - .setDisplayNameFldAddFilterMdl(displayName); - Assert.assertTrue(topicDetails.isAddFilterBtnAddFilterMdlEnabled(), - "isAddFilterBtnAddFilterMdlEnabled()"); - topicDetails - .clickAddFilterBtnAndCloseMdl(false) - .openSavedFiltersListMdl(); - Assert.assertTrue(topicDetails.isFilterVisibleAtSavedFiltersMdl(displayName), - "isFilterVisibleAtSavedFiltersMdl()"); - } - - @QaseId(14) - @Test(priority = 14) - public void checkApplyingSavedFilterWithinTopicMessages() { - String displayName = randomAlphabetic(5); - navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_FILTERS.getName()); - topicDetails - .openDetailsTab(MESSAGES) - .clickMessagesAddFiltersBtn() - .waitUntilAddFiltersMdlVisible() - .setFilterCodeFieldAddFilterMdl(randomAlphabetic(4)) - .selectSaveThisFilterCheckboxMdl(true) - .setDisplayNameFldAddFilterMdl(displayName) - .clickAddFilterBtnAndCloseMdl(false) - .openSavedFiltersListMdl() - .selectFilterAtSavedFiltersMdl(displayName) - .clickSelectFilterBtnAtSavedFiltersMdl(); - Assert.assertTrue(topicDetails.isActiveFilterVisible(displayName), "isActiveFilterVisible()"); - } - - @QaseId(11) - @Test(priority = 15) - public void checkShowInternalTopicsButton() { - navigateToTopics(); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(topicsList.isShowInternalRadioBtnSelected(), "isInternalRadioBtnSelected()"); - softly.assertTrue(topicsList.getInternalTopics().size() > 0, "getInternalTopics()"); - softly.assertTrue(topicsList.getNonInternalTopics().size() > 0, "getNonInternalTopics()"); - softly.assertAll(); - topicsList - .setShowInternalRadioButton(false); - softly.assertEquals(topicsList.getInternalTopics().size(), 0, "getInternalTopics()"); - softly.assertTrue(topicsList.getNonInternalTopics().size() > 0, "getNonInternalTopics()"); - softly.assertAll(); - } - - @QaseId(334) - @Test(priority = 16) - public void checkInternalTopicsNaming() { - navigateToTopics(); - SoftAssert softly = new SoftAssert(); - topicsList - .setShowInternalRadioButton(true) - .getInternalTopics() - .forEach(topic -> softly.assertTrue(topic.getName().startsWith("_"), - String.format("'%s' starts with '_'", topic.getName()))); - softly.assertAll(); - } - - @QaseId(56) - @Test(priority = 17) - public void checkRetentionBytesAccordingToMaxSizeOnDisk() { - navigateToTopics(); - topicsList - .clickAddTopicBtn(); - topicCreateEditForm - .waitUntilScreenReady() - .setTopicName(TOPIC_TO_CHECK_SETTINGS.getName()) - .setNumberOfPartitions(TOPIC_TO_CHECK_SETTINGS.getNumberOfPartitions()) - .setMaxMessageBytes(TOPIC_TO_CHECK_SETTINGS.getMaxMessageBytes()) - .clickCreateTopicBtn(); - topicDetails - .waitUntilScreenReady(); - TOPIC_LIST.add(TOPIC_TO_CHECK_SETTINGS); - topicDetails - .openDetailsTab(SETTINGS); - topicSettingsTab - .waitUntilScreenReady(); - SoftAssert softly = new SoftAssert(); - softly.assertEquals(topicSettingsTab.getValueByKey("retention.bytes"), - TOPIC_TO_CHECK_SETTINGS.getMaxSizeOnDisk().getOptionValue(), "getValueOfKey(retention.bytes)"); - softly.assertEquals(topicSettingsTab.getValueByKey("max.message.bytes"), - TOPIC_TO_CHECK_SETTINGS.getMaxMessageBytes(), "getValueOfKey(max.message.bytes)"); - softly.assertAll(); - TOPIC_TO_CHECK_SETTINGS - .setMaxSizeOnDisk(SIZE_1_GB) - .setMaxMessageBytes("1000056"); - topicDetails - .openDotMenu() - .clickEditSettingsMenu(); - topicCreateEditForm - .waitUntilScreenReady() - .setMaxSizeOnDiskInGB(TOPIC_TO_CHECK_SETTINGS.getMaxSizeOnDisk()) - .setMaxMessageBytes(TOPIC_TO_CHECK_SETTINGS.getMaxMessageBytes()) - .clickCreateTopicBtn(); - topicDetails - .waitUntilScreenReady() - .openDetailsTab(SETTINGS); - topicSettingsTab - .waitUntilScreenReady(); - softly.assertEquals(topicSettingsTab.getValueByKey("retention.bytes"), - TOPIC_TO_CHECK_SETTINGS.getMaxSizeOnDisk().getOptionValue(), "getValueOfKey(retention.bytes)"); - softly.assertEquals(topicSettingsTab.getValueByKey("max.message.bytes"), - TOPIC_TO_CHECK_SETTINGS.getMaxMessageBytes(), "getValueOfKey(max.message.bytes)"); - softly.assertAll(); - } - - @QaseId(247) - @Test(priority = 18) - public void recreateTopicFromTopicProfile() { - Topic topicToRecreate = new Topic() - .setName("topic-to-recreate-" + randomAlphabetic(5)) - .setNumberOfPartitions(1); - navigateToTopics(); - topicsList - .clickAddTopicBtn(); - topicCreateEditForm - .waitUntilScreenReady() - .setTopicName(topicToRecreate.getName()) - .setNumberOfPartitions(topicToRecreate.getNumberOfPartitions()) - .clickCreateTopicBtn(); - topicDetails - .waitUntilScreenReady(); - TOPIC_LIST.add(topicToRecreate); - topicDetails - .openDotMenu() - .clickRecreateTopicMenu(); - Assert.assertTrue(topicDetails.isConfirmationMdlVisible(), "isConfirmationMdlVisible()"); - topicDetails - .clickConfirmBtnMdl(); - Assert.assertTrue(topicDetails.isAlertWithMessageVisible(SUCCESS, - String.format("Topic %s successfully recreated!", topicToRecreate.getName())), - "isAlertWithMessageVisible()"); - } - - @QaseId(8) - @Test(priority = 19) - public void checkCopyTopicPossibility() { - Topic topicToCopy = new Topic() - .setName("topic-to-copy-" + randomAlphabetic(5)) - .setNumberOfPartitions(1); - navigateToTopics(); - topicsList - .getAnyNonInternalTopic() - .selectItem(true) - .clickCopySelectedTopicBtn(); - topicCreateEditForm - .waitUntilScreenReady(); - Assert.assertFalse(topicCreateEditForm.isCreateTopicButtonEnabled(), "isCreateTopicButtonEnabled()"); - topicCreateEditForm - .setTopicName(topicToCopy.getName()) - .setNumberOfPartitions(topicToCopy.getNumberOfPartitions()) - .clickCreateTopicBtn(); - topicDetails - .waitUntilScreenReady(); - TOPIC_LIST.add(topicToCopy); - SoftAssert softly = new SoftAssert(); - softly.assertTrue(topicDetails.isAlertWithMessageVisible(SUCCESS, "Topic successfully created."), - "isAlertWithMessageVisible()"); - softly.assertTrue(topicDetails.isTopicHeaderVisible(topicToCopy.getName()), "isTopicHeaderVisible()"); - softly.assertAll(); - } - - @AfterClass(alwaysRun = true) - public void afterClass() { - TOPIC_LIST.forEach(topic -> apiService.deleteTopic(topic.getName())); - } -} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/SmokeTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/SmokeTest.java new file mode 100644 index 0000000000..5193ecb25e --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/SmokeTest.java @@ -0,0 +1,115 @@ +package com.provectus.kafka.ui.smokesuite; + +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.BROKERS; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.KAFKA_CONNECT; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.SCHEMA_REGISTRY; +import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.TOPICS; +import static com.provectus.kafka.ui.settings.BaseSource.BASE_HOST; +import static com.provectus.kafka.ui.utilities.FileUtils.getResourceAsString; +import static com.provectus.kafka.ui.variables.Url.BROKERS_LIST_URL; +import static com.provectus.kafka.ui.variables.Url.CONSUMERS_LIST_URL; +import static com.provectus.kafka.ui.variables.Url.KAFKA_CONNECT_LIST_URL; +import static com.provectus.kafka.ui.variables.Url.KSQL_DB_LIST_URL; +import static com.provectus.kafka.ui.variables.Url.SCHEMA_REGISTRY_LIST_URL; +import static com.provectus.kafka.ui.variables.Url.TOPICS_LIST_URL; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.WebDriverRunner; +import com.provectus.kafka.ui.BaseTest; +import com.provectus.kafka.ui.models.Connector; +import com.provectus.kafka.ui.models.Schema; +import com.provectus.kafka.ui.models.Topic; +import com.provectus.kafka.ui.pages.panels.enums.MenuItem; +import io.qameta.allure.Step; +import io.qase.api.annotation.QaseId; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class SmokeTest extends BaseTest { + + private static final int BROKER_ID = 1; + private static final Schema TEST_SCHEMA = Schema.createSchemaAvro(); + private static final Topic TEST_TOPIC = new Topic() + .setName("new-topic-" + randomAlphabetic(5)) + .setNumberOfPartitions(1); + private static final Connector TEST_CONNECTOR = new Connector() + .setName("new-connector-" + randomAlphabetic(5)) + .setConfig(getResourceAsString("testData/connectors/config_for_create_connector_via_api.json")); + + @BeforeClass(alwaysRun = true) + public void beforeClass() { + apiService + .createTopic(TEST_TOPIC) + .createSchema(TEST_SCHEMA) + .createConnector(TEST_CONNECTOR); + } + + @QaseId(198) + @Test + public void checkBasePageElements() { + verifyElementsCondition( + Stream.concat(topPanel.getAllVisibleElements().stream(), naviSideBar.getAllMenuButtons().stream()) + .collect(Collectors.toList()), Condition.visible); + verifyElementsCondition( + Stream.concat(topPanel.getAllEnabledElements().stream(), naviSideBar.getAllMenuButtons().stream()) + .collect(Collectors.toList()), Condition.enabled); + } + + @QaseId(45) + @Test + public void checkUrlWhileNavigating() { + navigateToBrokers(); + verifyCurrentUrl(BROKERS_LIST_URL); + navigateToTopics(); + verifyCurrentUrl(TOPICS_LIST_URL); + navigateToConsumers(); + verifyCurrentUrl(CONSUMERS_LIST_URL); + navigateToSchemaRegistry(); + verifyCurrentUrl(SCHEMA_REGISTRY_LIST_URL); + navigateToConnectors(); + verifyCurrentUrl(KAFKA_CONNECT_LIST_URL); + navigateToKsqlDb(); + verifyCurrentUrl(KSQL_DB_LIST_URL); + } + + @QaseId(46) + @Test + public void checkPathWhileNavigating() { + navigateToBrokersAndOpenDetails(BROKER_ID); + verifyComponentsPath(BROKERS, String.format("Broker %d", BROKER_ID)); + navigateToTopicsAndOpenDetails(TEST_TOPIC.getName()); + verifyComponentsPath(TOPICS, TEST_TOPIC.getName()); + navigateToSchemaRegistryAndOpenDetails(TEST_SCHEMA.getName()); + verifyComponentsPath(SCHEMA_REGISTRY, TEST_SCHEMA.getName()); + navigateToConnectorsAndOpenDetails(TEST_CONNECTOR.getName()); + verifyComponentsPath(KAFKA_CONNECT, TEST_CONNECTOR.getName()); + } + + @Step + private void verifyCurrentUrl(String expectedUrl) { + String urlWithoutParameters = WebDriverRunner.getWebDriver().getCurrentUrl(); + if (urlWithoutParameters.contains("?")) { + urlWithoutParameters = urlWithoutParameters.substring(0, urlWithoutParameters.indexOf("?")); + } + Assert.assertEquals(urlWithoutParameters, String.format(expectedUrl, BASE_HOST), "getCurrentUrl()"); + } + + @Step + private void verifyComponentsPath(MenuItem menuItem, String expectedPath) { + Assert.assertEquals(naviSideBar.getPagePath(menuItem), expectedPath, + String.format("getPagePath() for %s", menuItem.getPageTitle().toUpperCase())); + } + + @AfterClass(alwaysRun = true) + public void afterClass() { + apiService + .deleteTopic(TEST_TOPIC.getName()) + .deleteSchema(TEST_SCHEMA.getName()) + .deleteConnector(TEST_CONNECTOR.getName()); + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/brokers/BrokersTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/brokers/BrokersTest.java new file mode 100644 index 0000000000..8fd1ffde15 --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/brokers/BrokersTest.java @@ -0,0 +1,41 @@ +package com.provectus.kafka.ui.smokesuite.brokers; + +import static com.provectus.kafka.ui.pages.brokers.BrokersDetails.DetailsTab.CONFIGS; + +import com.codeborne.selenide.Condition; +import com.provectus.kafka.ui.BaseTest; +import io.qase.api.annotation.QaseId; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class BrokersTest extends BaseTest { + + @QaseId(1) + @Test + public void checkBrokersOverview() { + navigateToBrokers(); + Assert.assertTrue(brokersList.getAllBrokers().size() > 0, "getAllBrokers()"); + verifyElementsCondition(brokersList.getAllVisibleElements(), Condition.visible); + verifyElementsCondition(brokersList.getAllEnabledElements(), Condition.enabled); + } + + @QaseId(85) + @Test + public void checkExistingBrokersInCluster() { + navigateToBrokers(); + Assert.assertTrue(brokersList.getAllBrokers().size() > 0, "getAllBrokers()"); + brokersList + .openBroker(1); + brokersDetails + .waitUntilScreenReady(); + verifyElementsCondition(brokersDetails.getAllVisibleElements(), Condition.visible); + verifyElementsCondition(brokersDetails.getAllEnabledElements(), Condition.enabled); + brokersDetails + .openDetailsTab(CONFIGS); + brokersConfigTab + .waitUntilScreenReady(); + verifyElementsCondition(brokersConfigTab.getColumnHeaders(), Condition.visible); + verifyElementsCondition(brokersConfigTab.getEditButtons(), Condition.enabled); + Assert.assertTrue(brokersConfigTab.isSearchByKeyVisible(), "isSearchByKeyVisible()"); + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/connectors/ConnectorsTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/connectors/ConnectorsTest.java new file mode 100644 index 0000000000..9ca3526c71 --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/connectors/ConnectorsTest.java @@ -0,0 +1,107 @@ +package com.provectus.kafka.ui.smokesuite.connectors; + +import static com.provectus.kafka.ui.pages.BasePage.AlertHeader.SUCCESS; +import static com.provectus.kafka.ui.utilities.FileUtils.getResourceAsString; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + +import com.provectus.kafka.ui.BaseTest; +import com.provectus.kafka.ui.models.Connector; +import com.provectus.kafka.ui.models.Topic; +import io.qase.api.annotation.QaseId; +import java.util.ArrayList; +import java.util.List; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class ConnectorsTest extends BaseTest { + + private static final List TOPIC_LIST = new ArrayList<>(); + private static final List CONNECTOR_LIST = new ArrayList<>(); + private static final String MESSAGE_CONTENT = "testData/topics/message_content_create_topic.json"; + private static final String MESSAGE_KEY = " "; + private static final Topic TOPIC_FOR_CREATE = new Topic() + .setName("topic-for-create-connector-" + randomAlphabetic(5)) + .setMessageValue(MESSAGE_CONTENT).setMessageKey(MESSAGE_KEY); + private static final Topic TOPIC_FOR_DELETE = new Topic() + .setName("topic-for-delete-connector-" + randomAlphabetic(5)) + .setMessageValue(MESSAGE_CONTENT).setMessageKey(MESSAGE_KEY); + private static final Topic TOPIC_FOR_UPDATE = new Topic() + .setName("topic-for-update-connector-" + randomAlphabetic(5)) + .setMessageValue(MESSAGE_CONTENT).setMessageKey(MESSAGE_KEY); + private static final Connector CONNECTOR_FOR_DELETE = new Connector() + .setName("connector-for-delete-" + randomAlphabetic(5)) + .setConfig(getResourceAsString("testData/connectors/delete_connector_config.json")); + private static final Connector CONNECTOR_FOR_UPDATE = new Connector() + .setName("connector-for-update-and-delete-" + randomAlphabetic(5)) + .setConfig(getResourceAsString("testData/connectors/config_for_create_connector_via_api.json")); + + @BeforeClass(alwaysRun = true) + public void beforeClass() { + TOPIC_LIST.addAll(List.of(TOPIC_FOR_CREATE, TOPIC_FOR_DELETE, TOPIC_FOR_UPDATE)); + TOPIC_LIST.forEach(topic -> apiService + .createTopic(topic) + .sendMessage(topic) + ); + CONNECTOR_LIST.addAll(List.of(CONNECTOR_FOR_DELETE, CONNECTOR_FOR_UPDATE)); + CONNECTOR_LIST.forEach(connector -> apiService.createConnector(connector)); + } + + @QaseId(42) + @Test + public void createConnector() { + Connector connectorForCreate = new Connector() + .setName("connector-for-create-" + randomAlphabetic(5)) + .setConfig(getResourceAsString("testData/connectors/config_for_create_connector.json")); + navigateToConnectors(); + kafkaConnectList + .clickCreateConnectorBtn(); + connectorCreateForm + .waitUntilScreenReady() + .setConnectorDetails(connectorForCreate.getName(), connectorForCreate.getConfig()) + .clickSubmitButton(); + connectorDetails + .waitUntilScreenReady(); + navigateToConnectorsAndOpenDetails(connectorForCreate.getName()); + Assert.assertTrue(connectorDetails.isConnectorHeaderVisible(connectorForCreate.getName()), + "isConnectorTitleVisible()"); + navigateToConnectors(); + Assert.assertTrue(kafkaConnectList.isConnectorVisible(CONNECTOR_FOR_DELETE.getName()), "isConnectorVisible()"); + CONNECTOR_LIST.add(connectorForCreate); + } + + @QaseId(196) + @Test + public void updateConnector() { + navigateToConnectorsAndOpenDetails(CONNECTOR_FOR_UPDATE.getName()); + connectorDetails + .openConfigTab() + .setConfig(CONNECTOR_FOR_UPDATE.getConfig()) + .clickSubmitButton(); + Assert.assertTrue(connectorDetails.isAlertWithMessageVisible(SUCCESS, "Config successfully updated."), + "isAlertWithMessageVisible()"); + navigateToConnectors(); + Assert.assertTrue(kafkaConnectList.isConnectorVisible(CONNECTOR_FOR_UPDATE.getName()), "isConnectorVisible()"); + } + + @QaseId(195) + @Test + public void deleteConnector() { + navigateToConnectorsAndOpenDetails(CONNECTOR_FOR_DELETE.getName()); + connectorDetails + .openDotMenu() + .clickDeleteBtn() + .clickConfirmBtn(); + navigateToConnectors(); + Assert.assertFalse(kafkaConnectList.isConnectorVisible(CONNECTOR_FOR_DELETE.getName()), "isConnectorVisible()"); + CONNECTOR_LIST.remove(CONNECTOR_FOR_DELETE); + } + + @AfterClass(alwaysRun = true) + public void afterClass() { + CONNECTOR_LIST.forEach(connector -> + apiService.deleteConnector(connector.getName())); + TOPIC_LIST.forEach(topic -> apiService.deleteTopic(topic.getName())); + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/ksqldb/KsqlDbTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/ksqldb/KsqlDbTest.java new file mode 100644 index 0000000000..d8bda606dc --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/ksqldb/KsqlDbTest.java @@ -0,0 +1,79 @@ +package com.provectus.kafka.ui.smokesuite.ksqldb; + +import static com.provectus.kafka.ui.pages.ksqldb.enums.KsqlQueryConfig.SHOW_TABLES; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + +import com.provectus.kafka.ui.BaseTest; +import com.provectus.kafka.ui.pages.ksqldb.models.Stream; +import com.provectus.kafka.ui.pages.ksqldb.models.Table; +import io.qase.api.annotation.QaseId; +import java.util.ArrayList; +import java.util.List; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.testng.asserts.SoftAssert; + +public class KsqlDbTest extends BaseTest { + + private static final Stream STREAM_FOR_CHECK_TABLES = new Stream() + .setName("STREAM_FOR_CHECK_TABLES_" + randomAlphabetic(4).toUpperCase()) + .setTopicName("TOPIC_FOR_STREAM_" + randomAlphabetic(4).toUpperCase()); + private static final Table FIRST_TABLE = new Table() + .setName("FIRST_TABLE" + randomAlphabetic(4).toUpperCase()) + .setStreamName(STREAM_FOR_CHECK_TABLES.getName()); + private static final Table SECOND_TABLE = new Table() + .setName("SECOND_TABLE" + randomAlphabetic(4).toUpperCase()) + .setStreamName(STREAM_FOR_CHECK_TABLES.getName()); + private static final List TOPIC_NAMES_LIST = new ArrayList<>(); + + @BeforeClass(alwaysRun = true) + public void beforeClass() { + apiService + .createStream(STREAM_FOR_CHECK_TABLES) + .createTables(FIRST_TABLE, SECOND_TABLE); + TOPIC_NAMES_LIST.addAll(List.of(STREAM_FOR_CHECK_TABLES.getTopicName(), + FIRST_TABLE.getName(), SECOND_TABLE.getName())); + } + + @QaseId(41) + @Test(priority = 1) + public void checkShowTablesRequestExecution() { + navigateToKsqlDb(); + ksqlDbList + .clickExecuteKsqlRequestBtn(); + ksqlQueryForm + .waitUntilScreenReady() + .setQuery(SHOW_TABLES.getQuery()) + .clickExecuteBtn(); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(ksqlQueryForm.areResultsVisible(), "areResultsVisible()"); + softly.assertTrue(ksqlQueryForm.getTableByName(FIRST_TABLE.getName()).isVisible(), "getTableName()"); + softly.assertTrue(ksqlQueryForm.getTableByName(SECOND_TABLE.getName()).isVisible(), "getTableName()"); + softly.assertAll(); + } + + @QaseId(86) + @Test(priority = 2) + public void clearResultsForExecutedRequest() { + navigateToKsqlDb(); + ksqlDbList + .clickExecuteKsqlRequestBtn(); + ksqlQueryForm + .waitUntilScreenReady() + .setQuery(SHOW_TABLES.getQuery()) + .clickExecuteBtn(); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(ksqlQueryForm.areResultsVisible(), "areResultsVisible()"); + softly.assertAll(); + ksqlQueryForm + .clickClearResultsBtn(); + softly.assertFalse(ksqlQueryForm.areResultsVisible(), "areResultsVisible()"); + softly.assertAll(); + } + + @AfterClass(alwaysRun = true) + public void afterClass() { + TOPIC_NAMES_LIST.forEach(topicName -> apiService.deleteTopic(topicName)); + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/schemas/SchemasTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/schemas/SchemasTest.java new file mode 100644 index 0000000000..0fc77e1f4b --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/schemas/SchemasTest.java @@ -0,0 +1,190 @@ +package com.provectus.kafka.ui.smokesuite.schemas; + +import static com.provectus.kafka.ui.utilities.FileUtils.fileToString; + +import com.codeborne.selenide.Condition; +import com.provectus.kafka.ui.BaseTest; +import com.provectus.kafka.ui.api.model.CompatibilityLevel; +import com.provectus.kafka.ui.models.Schema; +import io.qase.api.annotation.QaseId; +import java.util.ArrayList; +import java.util.List; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.testng.asserts.SoftAssert; + +public class SchemasTest extends BaseTest { + + private static final List SCHEMA_LIST = new ArrayList<>(); + private static final Schema AVRO_API = Schema.createSchemaAvro(); + private static final Schema JSON_API = Schema.createSchemaJson(); + private static final Schema PROTOBUF_API = Schema.createSchemaProtobuf(); + + @BeforeClass(alwaysRun = true) + public void beforeClass() { + SCHEMA_LIST.addAll(List.of(AVRO_API, JSON_API, PROTOBUF_API)); + SCHEMA_LIST.forEach(schema -> apiService.createSchema(schema)); + } + + @QaseId(43) + @Test(priority = 1) + public void createSchemaAvro() { + Schema schemaAvro = Schema.createSchemaAvro(); + navigateToSchemaRegistry(); + schemaRegistryList + .clickCreateSchema(); + schemaCreateForm + .setSubjectName(schemaAvro.getName()) + .setSchemaField(fileToString(schemaAvro.getValuePath())) + .selectSchemaTypeFromDropdown(schemaAvro.getType()) + .clickSubmitButton(); + schemaDetails + .waitUntilScreenReady(); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(schemaDetails.isSchemaHeaderVisible(schemaAvro.getName()), "isSchemaHeaderVisible()"); + softly.assertEquals(schemaDetails.getSchemaType(), schemaAvro.getType().getValue(), "getSchemaType()"); + softly.assertEquals(schemaDetails.getCompatibility(), CompatibilityLevel.CompatibilityEnum.BACKWARD.getValue(), + "getCompatibility()"); + softly.assertAll(); + navigateToSchemaRegistry(); + Assert.assertTrue(schemaRegistryList.isSchemaVisible(AVRO_API.getName()), "isSchemaVisible()"); + SCHEMA_LIST.add(schemaAvro); + } + + @QaseId(186) + @Test(priority = 2) + public void updateSchemaAvro() { + AVRO_API.setValuePath( + System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_avro_for_update.json"); + navigateToSchemaRegistryAndOpenDetails(AVRO_API.getName()); + schemaDetails + .openEditSchema(); + schemaCreateForm + .waitUntilScreenReady(); + verifyElementsCondition(schemaCreateForm.getAllDetailsPageElements(), Condition.visible); + SoftAssert softly = new SoftAssert(); + softly.assertFalse(schemaCreateForm.isSubmitBtnEnabled(), "isSubmitBtnEnabled()"); + softly.assertFalse(schemaCreateForm.isSchemaDropDownEnabled(), "isSchemaDropDownEnabled()"); + softly.assertAll(); + schemaCreateForm + .selectCompatibilityLevelFromDropdown(CompatibilityLevel.CompatibilityEnum.NONE) + .setNewSchemaValue(fileToString(AVRO_API.getValuePath())) + .clickSubmitButton(); + schemaDetails + .waitUntilScreenReady(); + Assert.assertEquals(schemaDetails.getCompatibility(), CompatibilityLevel.CompatibilityEnum.NONE.toString(), + "getCompatibility()"); + } + + @QaseId(44) + @Test(priority = 3) + public void compareVersionsOperation() { + navigateToSchemaRegistryAndOpenDetails(AVRO_API.getName()); + int latestVersion = schemaDetails + .waitUntilScreenReady() + .getLatestVersion(); + schemaDetails + .openCompareVersionMenu(); + int versionsNumberFromDdl = schemaCreateForm + .waitUntilScreenReady() + .openLeftVersionDdl() + .getVersionsNumberFromList(); + Assert.assertEquals(versionsNumberFromDdl, latestVersion, "Versions number is not matched"); + schemaCreateForm + .selectVersionFromDropDown(1); + Assert.assertEquals(schemaCreateForm.getMarkedLinesNumber(), 42, "getAllMarkedLines()"); + } + + @QaseId(187) + @Test(priority = 4) + public void deleteSchemaAvro() { + navigateToSchemaRegistryAndOpenDetails(AVRO_API.getName()); + schemaDetails + .removeSchema(); + schemaRegistryList + .waitUntilScreenReady(); + Assert.assertFalse(schemaRegistryList.isSchemaVisible(AVRO_API.getName()), "isSchemaVisible()"); + SCHEMA_LIST.remove(AVRO_API); + } + + @QaseId(89) + @Test(priority = 5) + public void createSchemaJson() { + Schema schemaJson = Schema.createSchemaJson(); + navigateToSchemaRegistry(); + schemaRegistryList + .clickCreateSchema(); + schemaCreateForm + .setSubjectName(schemaJson.getName()) + .setSchemaField(fileToString(schemaJson.getValuePath())) + .selectSchemaTypeFromDropdown(schemaJson.getType()) + .clickSubmitButton(); + schemaDetails + .waitUntilScreenReady(); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(schemaDetails.isSchemaHeaderVisible(schemaJson.getName()), "isSchemaHeaderVisible()"); + softly.assertEquals(schemaDetails.getSchemaType(), schemaJson.getType().getValue(), "getSchemaType()"); + softly.assertEquals(schemaDetails.getCompatibility(), CompatibilityLevel.CompatibilityEnum.BACKWARD.getValue(), + "getCompatibility()"); + softly.assertAll(); + navigateToSchemaRegistry(); + Assert.assertTrue(schemaRegistryList.isSchemaVisible(JSON_API.getName()), "isSchemaVisible()"); + SCHEMA_LIST.add(schemaJson); + } + + @QaseId(189) + @Test(priority = 6) + public void deleteSchemaJson() { + navigateToSchemaRegistryAndOpenDetails(JSON_API.getName()); + schemaDetails + .removeSchema(); + schemaRegistryList + .waitUntilScreenReady(); + Assert.assertFalse(schemaRegistryList.isSchemaVisible(JSON_API.getName()), "isSchemaVisible()"); + SCHEMA_LIST.remove(JSON_API); + } + + @QaseId(91) + @Test(priority = 7) + public void createSchemaProtobuf() { + Schema schemaProtobuf = Schema.createSchemaProtobuf(); + navigateToSchemaRegistry(); + schemaRegistryList + .clickCreateSchema(); + schemaCreateForm + .setSubjectName(schemaProtobuf.getName()) + .setSchemaField(fileToString(schemaProtobuf.getValuePath())) + .selectSchemaTypeFromDropdown(schemaProtobuf.getType()) + .clickSubmitButton(); + schemaDetails + .waitUntilScreenReady(); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(schemaDetails.isSchemaHeaderVisible(schemaProtobuf.getName()), "isSchemaHeaderVisible()"); + softly.assertEquals(schemaDetails.getSchemaType(), schemaProtobuf.getType().getValue(), "getSchemaType()"); + softly.assertEquals(schemaDetails.getCompatibility(), CompatibilityLevel.CompatibilityEnum.BACKWARD.getValue(), + "getCompatibility()"); + softly.assertAll(); + navigateToSchemaRegistry(); + Assert.assertTrue(schemaRegistryList.isSchemaVisible(PROTOBUF_API.getName()), "isSchemaVisible()"); + SCHEMA_LIST.add(schemaProtobuf); + } + + @QaseId(223) + @Test(priority = 8) + public void deleteSchemaProtobuf() { + navigateToSchemaRegistryAndOpenDetails(PROTOBUF_API.getName()); + schemaDetails + .removeSchema(); + schemaRegistryList + .waitUntilScreenReady(); + Assert.assertFalse(schemaRegistryList.isSchemaVisible(PROTOBUF_API.getName()), "isSchemaVisible()"); + SCHEMA_LIST.remove(PROTOBUF_API); + } + + @AfterClass(alwaysRun = true) + public void afterClass() { + SCHEMA_LIST.forEach(schema -> apiService.deleteSchema(schema.getName())); + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/topics/MessagesTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/topics/MessagesTest.java new file mode 100644 index 0000000000..3bbc7e7cd3 --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/topics/MessagesTest.java @@ -0,0 +1,275 @@ +package com.provectus.kafka.ui.smokesuite.topics; + +import static com.provectus.kafka.ui.pages.BasePage.AlertHeader.SUCCESS; +import static com.provectus.kafka.ui.pages.topics.TopicDetails.TopicMenu.MESSAGES; +import static com.provectus.kafka.ui.pages.topics.TopicDetails.TopicMenu.OVERVIEW; +import static com.provectus.kafka.ui.utilities.TimeUtils.waitUntilNewMinuteStarted; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + +import com.provectus.kafka.ui.BaseTest; +import com.provectus.kafka.ui.models.Topic; +import com.provectus.kafka.ui.pages.topics.TopicDetails; +import io.qameta.allure.Issue; +import io.qameta.allure.Step; +import io.qase.api.annotation.QaseId; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.IntStream; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Ignore; +import org.testng.annotations.Test; +import org.testng.asserts.SoftAssert; + +public class MessagesTest extends BaseTest { + + private static final Topic TOPIC_FOR_MESSAGES = new Topic() + .setName("topic-with-clean-message-attribute-" + randomAlphabetic(5)) + .setMessageKey(randomAlphabetic(5)) + .setMessageValue(randomAlphabetic(10)); + private static final Topic TOPIC_TO_CLEAR_AND_PURGE_MESSAGES = new Topic() + .setName("topic-to-clear-and-purge-messages-" + randomAlphabetic(5)) + .setMessageKey(randomAlphabetic(5)) + .setMessageValue(randomAlphabetic(10)); + private static final Topic TOPIC_FOR_CHECK_FILTERS = new Topic() + .setName("topic-for-check-filters-" + randomAlphabetic(5)) + .setMessageKey(randomAlphabetic(5)) + .setMessageValue(randomAlphabetic(10)); + private static final Topic TOPIC_TO_RECREATE = new Topic() + .setName("topic-to-recreate-attribute-" + randomAlphabetic(5)) + .setMessageKey(randomAlphabetic(5)) + .setMessageValue(randomAlphabetic(10)); + private static final Topic TOPIC_FOR_CHECK_MESSAGES_COUNT = new Topic() + .setName("topic-for-check-messages-count" + randomAlphabetic(5)) + .setMessageKey(randomAlphabetic(5)) + .setMessageValue(randomAlphabetic(10)); + private static final List TOPIC_LIST = new ArrayList<>(); + + @BeforeClass(alwaysRun = true) + public void beforeClass() { + TOPIC_LIST.addAll(List.of(TOPIC_FOR_MESSAGES, TOPIC_FOR_CHECK_FILTERS, TOPIC_TO_CLEAR_AND_PURGE_MESSAGES, + TOPIC_TO_RECREATE, TOPIC_FOR_CHECK_MESSAGES_COUNT)); + TOPIC_LIST.forEach(topic -> apiService.createTopic(topic)); + IntStream.range(1, 3).forEach(i -> apiService.sendMessage(TOPIC_FOR_CHECK_FILTERS)); + waitUntilNewMinuteStarted(); + IntStream.range(1, 3).forEach(i -> apiService.sendMessage(TOPIC_FOR_CHECK_FILTERS)); + IntStream.range(1, 110).forEach(i -> apiService.sendMessage(TOPIC_FOR_CHECK_MESSAGES_COUNT)); + } + + @QaseId(222) + @Test(priority = 1) + public void produceMessageCheck() { + navigateToTopicsAndOpenDetails(TOPIC_FOR_MESSAGES.getName()); + topicDetails + .openDetailsTab(MESSAGES); + produceMessage(TOPIC_FOR_MESSAGES); + Assert.assertEquals(topicDetails.getMessageByKey(TOPIC_FOR_MESSAGES.getMessageKey()).getValue(), + TOPIC_FOR_MESSAGES.getMessageValue(), "message.getValue()"); + } + + @QaseId(19) + @Test(priority = 2) + public void clearMessageCheck() { + navigateToTopicsAndOpenDetails(TOPIC_FOR_MESSAGES.getName()); + topicDetails + .openDetailsTab(OVERVIEW); + int messageAmount = topicDetails.getMessageCountAmount(); + produceMessage(TOPIC_FOR_MESSAGES); + Assert.assertEquals(topicDetails.getMessageCountAmount(), messageAmount + 1, "getMessageCountAmount()"); + topicDetails + .openDotMenu() + .clickClearMessagesMenu() + .clickConfirmBtnMdl() + .waitUntilScreenReady(); + Assert.assertEquals(topicDetails.getMessageCountAmount(), 0, "getMessageCountAmount()"); + } + + @QaseId(239) + @Test(priority = 3) + public void checkClearTopicMessage() { + navigateToTopicsAndOpenDetails(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()); + topicDetails + .openDetailsTab(OVERVIEW); + produceMessage(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES); + navigateToTopics(); + Assert.assertEquals(topicsList.getTopicItem(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()).getNumberOfMessages(), 1, + "getNumberOfMessages()"); + topicsList + .openDotMenuByTopicName(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()) + .clickClearMessagesBtn() + .clickConfirmBtnMdl(); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(topicsList.isAlertWithMessageVisible(SUCCESS, + String.format("%s messages have been successfully cleared!", TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName())), + "isAlertWithMessageVisible()"); + softly.assertEquals(topicsList.getTopicItem(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()).getNumberOfMessages(), 0, + "getNumberOfMessages()"); + softly.assertAll(); + } + + @QaseId(10) + @Test(priority = 4) + public void checkPurgeMessagePossibility() { + navigateToTopics(); + int messageAmount = topicsList.getTopicItem(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()).getNumberOfMessages(); + topicsList + .openTopic(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()); + topicDetails + .openDetailsTab(OVERVIEW); + produceMessage(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES); + navigateToTopics(); + Assert.assertEquals(topicsList.getTopicItem(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()).getNumberOfMessages(), + messageAmount + 1, "getNumberOfMessages()"); + topicsList + .getTopicItem(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()) + .selectItem(true) + .clickPurgeMessagesOfSelectedTopicsBtn(); + Assert.assertTrue(topicsList.isConfirmationMdlVisible(), "isConfirmationMdlVisible()"); + topicsList + .clickCancelBtnMdl() + .clickPurgeMessagesOfSelectedTopicsBtn() + .clickConfirmBtnMdl(); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(topicsList.isAlertWithMessageVisible(SUCCESS, + String.format("%s messages have been successfully cleared!", TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName())), + "isAlertWithMessageVisible()"); + softly.assertEquals(topicsList.getTopicItem(TOPIC_TO_CLEAR_AND_PURGE_MESSAGES.getName()).getNumberOfMessages(), 0, + "getNumberOfMessages()"); + softly.assertAll(); + } + + @Ignore + @Issue("https://github.com/provectus/kafka-ui/issues/2394") + @QaseId(15) + @Test(priority = 6) + public void checkMessageFilteringByOffset() { + navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_FILTERS.getName()); + topicDetails + .openDetailsTab(MESSAGES); + TopicDetails.MessageGridItem secondMessage = topicDetails.getMessageByOffset(1); + topicDetails + .selectSeekTypeDdlMessagesTab("Offset") + .setSeekTypeValueFldMessagesTab(String.valueOf(secondMessage.getOffset())) + .clickSubmitFiltersBtnMessagesTab(); + SoftAssert softly = new SoftAssert(); + topicDetails.getAllMessages().forEach(message -> + softly.assertTrue(message.getOffset() == secondMessage.getOffset() + || message.getOffset() > secondMessage.getOffset(), + String.format("Expected offset is: %s, but found: %s", secondMessage.getOffset(), message.getOffset()))); + softly.assertAll(); + } + + @Ignore + @Issue("https://github.com/provectus/kafka-ui/issues/3215") + @Issue("https://github.com/provectus/kafka-ui/issues/2345") + @QaseId(16) + @Test(priority = 7) + public void checkMessageFilteringByTimestamp() { + navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_FILTERS.getName()); + topicDetails + .openDetailsTab(MESSAGES); + LocalDateTime firstTimestamp = topicDetails.getMessageByOffset(0).getTimestamp(); + List nextMessages = topicDetails.getAllMessages().stream() + .filter(message -> message.getTimestamp().getMinute() != firstTimestamp.getMinute()) + .toList(); + LocalDateTime nextTimestamp = nextMessages.stream() + .findFirst().orElseThrow().getTimestamp(); + topicDetails + .selectSeekTypeDdlMessagesTab("Timestamp") + .openCalendarSeekType() + .selectDateAndTimeByCalendar(nextTimestamp) + .clickSubmitFiltersBtnMessagesTab(); + SoftAssert softly = new SoftAssert(); + topicDetails.getAllMessages().forEach(message -> + softly.assertTrue(message.getTimestamp().isEqual(nextTimestamp) + || message.getTimestamp().isAfter(nextTimestamp), + String.format("Expected that %s is not before %s.", message.getTimestamp(), nextTimestamp))); + softly.assertAll(); + } + + @QaseId(246) + @Test(priority = 8) + public void checkClearTopicMessageFromOverviewTab() { + navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_FILTERS.getName()); + topicDetails + .openDetailsTab(OVERVIEW) + .openDotMenu() + .clickClearMessagesMenu() + .clickConfirmBtnMdl(); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(topicDetails.isAlertWithMessageVisible(SUCCESS, + String.format("%s messages have been successfully cleared!", TOPIC_FOR_CHECK_FILTERS.getName())), + "isAlertWithMessageVisible()"); + softly.assertEquals(topicDetails.getMessageCountAmount(), 0, + "getMessageCountAmount()= " + topicDetails.getMessageCountAmount()); + softly.assertAll(); + } + + @QaseId(240) + @Test(priority = 9) + public void checkRecreateTopic() { + navigateToTopicsAndOpenDetails(TOPIC_TO_RECREATE.getName()); + topicDetails + .openDetailsTab(OVERVIEW); + produceMessage(TOPIC_TO_RECREATE); + navigateToTopics(); + Assert.assertEquals(topicsList.getTopicItem(TOPIC_TO_RECREATE.getName()).getNumberOfMessages(), 1, + "getNumberOfMessages()"); + topicsList + .openDotMenuByTopicName(TOPIC_TO_RECREATE.getName()) + .clickRecreateTopicBtn() + .clickConfirmBtnMdl(); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(topicDetails.isAlertWithMessageVisible(SUCCESS, + String.format("Topic %s successfully recreated!", TOPIC_TO_RECREATE.getName())), + "isAlertWithMessageVisible()"); + softly.assertEquals(topicsList.getTopicItem(TOPIC_TO_RECREATE.getName()).getNumberOfMessages(), 0, + "getNumberOfMessages()"); + softly.assertAll(); + } + + @Ignore + @Issue("https://github.com/provectus/kafka-ui/issues/3129") + @QaseId(267) + @Test(priority = 10) + public void checkMessagesCountPerPageWithinTopic() { + navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_MESSAGES_COUNT.getName()); + topicDetails + .openDetailsTab(MESSAGES); + int messagesPerPage = topicDetails.getAllMessages().size(); + SoftAssert softly = new SoftAssert(); + softly.assertEquals(messagesPerPage, 100, "getAllMessages()"); + softly.assertFalse(topicDetails.isBackButtonEnabled(), "isBackButtonEnabled()"); + softly.assertTrue(topicDetails.isNextButtonEnabled(), "isNextButtonEnabled()"); + softly.assertAll(); + int lastOffsetOnPage = topicDetails.getAllMessages() + .get(messagesPerPage - 1).getOffset(); + topicDetails + .clickNextButton(); + softly.assertEquals(topicDetails.getAllMessages().stream().findFirst().orElseThrow().getOffset(), + lastOffsetOnPage + 1, "findFirst().getOffset()"); + softly.assertTrue(topicDetails.isBackButtonEnabled(), "isBackButtonEnabled()"); + softly.assertFalse(topicDetails.isNextButtonEnabled(), "isNextButtonEnabled()"); + softly.assertAll(); + } + + @Step + private void produceMessage(Topic topic) { + topicDetails + .clickProduceMessageBtn(); + produceMessagePanel + .waitUntilScreenReady() + .setKeyField(topic.getMessageKey()) + .setValueFiled(topic.getMessageValue()) + .submitProduceMessage(); + topicDetails + .waitUntilScreenReady(); + } + + @AfterClass(alwaysRun = true) + public void afterClass() { + TOPIC_LIST.forEach(topic -> apiService.deleteTopic(topic.getName())); + } +} diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/topics/TopicsTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/topics/TopicsTest.java new file mode 100644 index 0000000000..ad20f595a4 --- /dev/null +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokesuite/topics/TopicsTest.java @@ -0,0 +1,500 @@ +package com.provectus.kafka.ui.smokesuite.topics; + +import static com.provectus.kafka.ui.pages.BasePage.AlertHeader.SUCCESS; +import static com.provectus.kafka.ui.pages.topics.TopicDetails.TopicMenu.CONSUMERS; +import static com.provectus.kafka.ui.pages.topics.TopicDetails.TopicMenu.MESSAGES; +import static com.provectus.kafka.ui.pages.topics.TopicDetails.TopicMenu.SETTINGS; +import static com.provectus.kafka.ui.pages.topics.enums.CleanupPolicyValue.COMPACT; +import static com.provectus.kafka.ui.pages.topics.enums.CleanupPolicyValue.DELETE; +import static com.provectus.kafka.ui.pages.topics.enums.CustomParameterType.COMPRESSION_TYPE; +import static com.provectus.kafka.ui.pages.topics.enums.MaxSizeOnDisk.NOT_SET; +import static com.provectus.kafka.ui.pages.topics.enums.MaxSizeOnDisk.SIZE_1_GB; +import static com.provectus.kafka.ui.pages.topics.enums.MaxSizeOnDisk.SIZE_50_GB; +import static com.provectus.kafka.ui.pages.topics.enums.TimeToRetain.BTN_2_DAYS; +import static com.provectus.kafka.ui.pages.topics.enums.TimeToRetain.BTN_7_DAYS; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import static org.apache.commons.lang3.RandomUtils.nextInt; + +import com.codeborne.selenide.Condition; +import com.provectus.kafka.ui.BaseTest; +import com.provectus.kafka.ui.models.Topic; +import io.qameta.allure.Issue; +import io.qase.api.annotation.QaseId; +import java.util.ArrayList; +import java.util.List; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Ignore; +import org.testng.annotations.Test; +import org.testng.asserts.SoftAssert; + +public class TopicsTest extends BaseTest { + + private static final Topic TOPIC_TO_CREATE = new Topic() + .setName("new-topic-" + randomAlphabetic(5)) + .setNumberOfPartitions(1) + .setCustomParameterType(COMPRESSION_TYPE) + .setCustomParameterValue("producer") + .setCleanupPolicyValue(DELETE); + private static final Topic TOPIC_TO_UPDATE_AND_DELETE = new Topic() + .setName("topic-to-update-and-delete-" + randomAlphabetic(5)) + .setNumberOfPartitions(1) + .setCleanupPolicyValue(DELETE) + .setTimeToRetain(BTN_7_DAYS) + .setMaxSizeOnDisk(NOT_SET) + .setMaxMessageBytes("1048588") + .setMessageKey(randomAlphabetic(5)) + .setMessageValue(randomAlphabetic(10)); + private static final Topic TOPIC_TO_CHECK_SETTINGS = new Topic() + .setName("new-topic-" + randomAlphabetic(5)) + .setNumberOfPartitions(1) + .setMaxMessageBytes("1000012") + .setMaxSizeOnDisk(NOT_SET); + private static final Topic TOPIC_FOR_CHECK_FILTERS = new Topic() + .setName("topic-for-check-filters-" + randomAlphabetic(5)); + private static final Topic TOPIC_FOR_DELETE = new Topic() + .setName("topic-to-delete-" + randomAlphabetic(5)); + private static final List TOPIC_LIST = new ArrayList<>(); + + @BeforeClass(alwaysRun = true) + public void beforeClass() { + TOPIC_LIST.addAll(List.of(TOPIC_TO_UPDATE_AND_DELETE, TOPIC_FOR_DELETE, TOPIC_FOR_CHECK_FILTERS)); + TOPIC_LIST.forEach(topic -> apiService.createTopic(topic)); + } + + @QaseId(199) + @Test(priority = 1) + public void createTopic() { + navigateToTopics(); + topicsList + .clickAddTopicBtn(); + topicCreateEditForm + .waitUntilScreenReady() + .setTopicName(TOPIC_TO_CREATE.getName()) + .setNumberOfPartitions(TOPIC_TO_CREATE.getNumberOfPartitions()) + .selectCleanupPolicy(TOPIC_TO_CREATE.getCleanupPolicyValue()) + .clickSaveTopicBtn(); + navigateToTopicsAndOpenDetails(TOPIC_TO_CREATE.getName()); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(topicDetails.isTopicHeaderVisible(TOPIC_TO_CREATE.getName()), "isTopicHeaderVisible()"); + softly.assertEquals(topicDetails.getCleanUpPolicy(), TOPIC_TO_CREATE.getCleanupPolicyValue().toString(), + "getCleanUpPolicy()"); + softly.assertEquals(topicDetails.getPartitions(), TOPIC_TO_CREATE.getNumberOfPartitions(), "getPartitions()"); + softly.assertAll(); + navigateToTopics(); + Assert.assertTrue(topicsList.isTopicVisible(TOPIC_TO_CREATE.getName()), "isTopicVisible()"); + TOPIC_LIST.add(TOPIC_TO_CREATE); + } + + @QaseId(7) + @Test(priority = 2) + void checkAvailableOperations() { + navigateToTopics(); + topicsList + .getTopicItem(TOPIC_TO_UPDATE_AND_DELETE.getName()) + .selectItem(true); + verifyElementsCondition(topicsList.getActionButtons(), Condition.enabled); + topicsList + .getTopicItem(TOPIC_FOR_CHECK_FILTERS.getName()) + .selectItem(true); + Assert.assertFalse(topicsList.isCopySelectedTopicBtnEnabled(), "isCopySelectedTopicBtnEnabled()"); + } + + @Ignore + @Issue("https://github.com/provectus/kafka-ui/issues/3071") + @QaseId(268) + @Test(priority = 3) + public void checkCustomParametersWithinEditExistingTopic() { + navigateToTopicsAndOpenDetails(TOPIC_TO_UPDATE_AND_DELETE.getName()); + topicDetails + .openDotMenu() + .clickEditSettingsMenu(); + SoftAssert softly = new SoftAssert(); + topicCreateEditForm + .waitUntilScreenReady() + .clickAddCustomParameterTypeButton() + .openCustomParameterTypeDdl() + .getAllDdlOptions() + .forEach(option -> + softly.assertTrue(!option.is(Condition.attribute("disabled")), + option.getText() + " is enabled:")); + softly.assertAll(); + } + + @QaseId(197) + @Test(priority = 4) + public void updateTopic() { + navigateToTopicsAndOpenDetails(TOPIC_TO_UPDATE_AND_DELETE.getName()); + topicDetails + .openDotMenu() + .clickEditSettingsMenu(); + topicCreateEditForm + .waitUntilScreenReady(); + SoftAssert softly = new SoftAssert(); + softly.assertEquals(topicCreateEditForm.getCleanupPolicy(), + TOPIC_TO_UPDATE_AND_DELETE.getCleanupPolicyValue().getVisibleText(), "getCleanupPolicy()"); + softly.assertEquals(topicCreateEditForm.getTimeToRetain(), + TOPIC_TO_UPDATE_AND_DELETE.getTimeToRetain().getValue(), "getTimeToRetain()"); + softly.assertEquals(topicCreateEditForm.getMaxSizeOnDisk(), + TOPIC_TO_UPDATE_AND_DELETE.getMaxSizeOnDisk().getVisibleText(), "getMaxSizeOnDisk()"); + softly.assertEquals(topicCreateEditForm.getMaxMessageBytes(), + TOPIC_TO_UPDATE_AND_DELETE.getMaxMessageBytes(), "getMaxMessageBytes()"); + softly.assertAll(); + TOPIC_TO_UPDATE_AND_DELETE + .setCleanupPolicyValue(COMPACT) + .setTimeToRetain(BTN_2_DAYS) + .setMaxSizeOnDisk(SIZE_50_GB).setMaxMessageBytes("1048589"); + topicCreateEditForm + .selectCleanupPolicy((TOPIC_TO_UPDATE_AND_DELETE.getCleanupPolicyValue())) + .setTimeToRetainDataByButtons(TOPIC_TO_UPDATE_AND_DELETE.getTimeToRetain()) + .setMaxSizeOnDiskInGB(TOPIC_TO_UPDATE_AND_DELETE.getMaxSizeOnDisk()) + .setMaxMessageBytes(TOPIC_TO_UPDATE_AND_DELETE.getMaxMessageBytes()) + .clickSaveTopicBtn(); + softly.assertTrue(topicDetails.isAlertWithMessageVisible(SUCCESS, "Topic successfully updated."), + "isAlertWithMessageVisible()"); + softly.assertTrue(topicDetails.isTopicHeaderVisible(TOPIC_TO_UPDATE_AND_DELETE.getName()), + "isTopicHeaderVisible()"); + softly.assertAll(); + topicDetails + .waitUntilScreenReady(); + navigateToTopicsAndOpenDetails(TOPIC_TO_UPDATE_AND_DELETE.getName()); + topicDetails + .openDotMenu() + .clickEditSettingsMenu(); + softly.assertFalse(topicCreateEditForm.isNameFieldEnabled(), "isNameFieldEnabled()"); + softly.assertEquals(topicCreateEditForm.getCleanupPolicy(), + TOPIC_TO_UPDATE_AND_DELETE.getCleanupPolicyValue().getVisibleText(), "getCleanupPolicy()"); + softly.assertEquals(topicCreateEditForm.getTimeToRetain(), + TOPIC_TO_UPDATE_AND_DELETE.getTimeToRetain().getValue(), "getTimeToRetain()"); + softly.assertEquals(topicCreateEditForm.getMaxSizeOnDisk(), + TOPIC_TO_UPDATE_AND_DELETE.getMaxSizeOnDisk().getVisibleText(), "getMaxSizeOnDisk()"); + softly.assertEquals(topicCreateEditForm.getMaxMessageBytes(), + TOPIC_TO_UPDATE_AND_DELETE.getMaxMessageBytes(), "getMaxMessageBytes()"); + softly.assertAll(); + } + + @QaseId(242) + @Test(priority = 5) + public void removeTopicFromTopicList() { + navigateToTopics(); + topicsList + .openDotMenuByTopicName(TOPIC_TO_UPDATE_AND_DELETE.getName()) + .clickRemoveTopicBtn() + .clickConfirmBtnMdl(); + Assert.assertTrue(topicsList.isAlertWithMessageVisible(SUCCESS, + String.format("Topic %s successfully deleted!", TOPIC_TO_UPDATE_AND_DELETE.getName())), + "isAlertWithMessageVisible()"); + TOPIC_LIST.remove(TOPIC_TO_UPDATE_AND_DELETE); + } + + @QaseId(207) + @Test(priority = 6) + public void deleteTopic() { + navigateToTopicsAndOpenDetails(TOPIC_FOR_DELETE.getName()); + topicDetails + .openDotMenu() + .clickDeleteTopicMenu() + .clickConfirmBtnMdl(); + navigateToTopics(); + Assert.assertFalse(topicsList.isTopicVisible(TOPIC_FOR_DELETE.getName()), "isTopicVisible"); + TOPIC_LIST.remove(TOPIC_FOR_DELETE); + } + + @QaseId(20) + @Test(priority = 7) + public void redirectToConsumerFromTopic() { + String topicName = "source-activities"; + String consumerGroupId = "connect-sink_postgres_activities"; + navigateToTopicsAndOpenDetails(topicName); + topicDetails + .openDetailsTab(CONSUMERS) + .openConsumerGroup(consumerGroupId); + consumersDetails + .waitUntilScreenReady(); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(consumersDetails.isRedirectedConsumerTitleVisible(consumerGroupId), + "isRedirectedConsumerTitleVisible()"); + softly.assertTrue(consumersDetails.isTopicInConsumersDetailsVisible(topicName), + "isTopicInConsumersDetailsVisible()"); + softly.assertAll(); + } + + @QaseId(4) + @Test(priority = 8) + public void checkTopicCreatePossibility() { + navigateToTopics(); + topicsList + .clickAddTopicBtn(); + topicCreateEditForm + .waitUntilScreenReady(); + Assert.assertFalse(topicCreateEditForm.isCreateTopicButtonEnabled(), "isCreateTopicButtonEnabled()"); + topicCreateEditForm + .setTopicName("testName"); + Assert.assertFalse(topicCreateEditForm.isCreateTopicButtonEnabled(), "isCreateTopicButtonEnabled()"); + topicCreateEditForm + .setTopicName(null) + .setNumberOfPartitions(nextInt(1, 10)); + Assert.assertFalse(topicCreateEditForm.isCreateTopicButtonEnabled(), "isCreateTopicButtonEnabled()"); + topicCreateEditForm + .setTopicName("testName"); + Assert.assertTrue(topicCreateEditForm.isCreateTopicButtonEnabled(), "isCreateTopicButtonEnabled()"); + } + + @QaseId(266) + @Test(priority = 9) + public void checkTimeToRetainDataCustomValueWithEditingTopic() { + Topic topicToRetainData = new Topic() + .setName("topic-to-retain-data-" + randomAlphabetic(5)) + .setTimeToRetainData("86400000"); + navigateToTopics(); + topicsList + .clickAddTopicBtn(); + topicCreateEditForm + .waitUntilScreenReady() + .setTopicName(topicToRetainData.getName()) + .setNumberOfPartitions(1) + .setTimeToRetainDataInMs("604800000"); + Assert.assertEquals(topicCreateEditForm.getTimeToRetain(), "604800000", "getTimeToRetain()"); + topicCreateEditForm + .setTimeToRetainDataInMs(topicToRetainData.getTimeToRetainData()) + .clickSaveTopicBtn(); + topicDetails + .waitUntilScreenReady() + .openDotMenu() + .clickEditSettingsMenu(); + Assert.assertEquals(topicCreateEditForm.getTimeToRetain(), topicToRetainData.getTimeToRetainData(), + "getTimeToRetain()"); + topicDetails + .openDetailsTab(SETTINGS); + Assert.assertEquals(topicDetails.getSettingsGridValueByKey("retention.ms"), topicToRetainData.getTimeToRetainData(), + "getSettingsGridValueByKey()"); + TOPIC_LIST.add(topicToRetainData); + } + + @QaseId(6) + @Test(priority = 10) + public void checkCustomParametersWithinCreateNewTopic() { + navigateToTopics(); + topicsList + .clickAddTopicBtn(); + topicCreateEditForm + .waitUntilScreenReady() + .setTopicName(TOPIC_TO_CREATE.getName()) + .clickAddCustomParameterTypeButton() + .setCustomParameterType(TOPIC_TO_CREATE.getCustomParameterType()); + Assert.assertTrue(topicCreateEditForm.isDeleteCustomParameterButtonEnabled(), + "isDeleteCustomParameterButtonEnabled()"); + topicCreateEditForm + .clearCustomParameterValue(); + Assert.assertTrue(topicCreateEditForm.isValidationMessageCustomParameterValueVisible(), + "isValidationMessageCustomParameterValueVisible()"); + } + + @QaseId(2) + @Test(priority = 11) + public void checkTopicListElements() { + navigateToTopics(); + verifyElementsCondition(topicsList.getAllVisibleElements(), Condition.visible); + verifyElementsCondition(topicsList.getAllEnabledElements(), Condition.enabled); + } + + @QaseId(12) + @Test(priority = 12) + public void addNewFilterWithinTopic() { + String filterName = randomAlphabetic(5); + navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_FILTERS.getName()); + topicDetails + .openDetailsTab(MESSAGES) + .clickMessagesAddFiltersBtn() + .waitUntilAddFiltersMdlVisible(); + verifyElementsCondition(topicDetails.getAllAddFilterModalVisibleElements(), Condition.visible); + verifyElementsCondition(topicDetails.getAllAddFilterModalEnabledElements(), Condition.enabled); + verifyElementsCondition(topicDetails.getAllAddFilterModalDisabledElements(), Condition.disabled); + Assert.assertFalse(topicDetails.isSaveThisFilterCheckBoxSelected(), "isSaveThisFilterCheckBoxSelected()"); + topicDetails + .setFilterCodeFieldAddFilterMdl(filterName); + Assert.assertTrue(topicDetails.isAddFilterBtnAddFilterMdlEnabled(), "isAddFilterBtnAddFilterMdlEnabled()"); + topicDetails.clickAddFilterBtnAndCloseMdl(true); + Assert.assertTrue(topicDetails.isActiveFilterVisible(filterName), "isActiveFilterVisible()"); + } + + @QaseId(13) + @Test(priority = 13) + public void checkFilterSavingWithinSavedFilters() { + String displayName = randomAlphabetic(5); + navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_FILTERS.getName()); + topicDetails + .openDetailsTab(MESSAGES) + .clickMessagesAddFiltersBtn() + .waitUntilAddFiltersMdlVisible() + .setFilterCodeFieldAddFilterMdl(randomAlphabetic(4)) + .selectSaveThisFilterCheckboxMdl(true) + .setDisplayNameFldAddFilterMdl(displayName); + Assert.assertTrue(topicDetails.isAddFilterBtnAddFilterMdlEnabled(), + "isAddFilterBtnAddFilterMdlEnabled()"); + topicDetails + .clickAddFilterBtnAndCloseMdl(false) + .openSavedFiltersListMdl(); + Assert.assertTrue(topicDetails.isFilterVisibleAtSavedFiltersMdl(displayName), + "isFilterVisibleAtSavedFiltersMdl()"); + } + + @QaseId(14) + @Test(priority = 14) + public void checkApplyingSavedFilterWithinTopicMessages() { + String displayName = randomAlphabetic(5); + navigateToTopicsAndOpenDetails(TOPIC_FOR_CHECK_FILTERS.getName()); + topicDetails + .openDetailsTab(MESSAGES) + .clickMessagesAddFiltersBtn() + .waitUntilAddFiltersMdlVisible() + .setFilterCodeFieldAddFilterMdl(randomAlphabetic(4)) + .selectSaveThisFilterCheckboxMdl(true) + .setDisplayNameFldAddFilterMdl(displayName) + .clickAddFilterBtnAndCloseMdl(false) + .openSavedFiltersListMdl() + .selectFilterAtSavedFiltersMdl(displayName) + .clickSelectFilterBtnAtSavedFiltersMdl(); + Assert.assertTrue(topicDetails.isActiveFilterVisible(displayName), "isActiveFilterVisible()"); + } + + @QaseId(11) + @Test(priority = 15) + public void checkShowInternalTopicsButton() { + navigateToTopics(); + topicsList + .setShowInternalRadioButton(true); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(topicsList.getInternalTopics().size() > 0, "getInternalTopics()"); + softly.assertTrue(topicsList.getNonInternalTopics().size() > 0, "getNonInternalTopics()"); + softly.assertAll(); + topicsList + .setShowInternalRadioButton(false); + softly.assertEquals(topicsList.getInternalTopics().size(), 0, "getInternalTopics()"); + softly.assertTrue(topicsList.getNonInternalTopics().size() > 0, "getNonInternalTopics()"); + softly.assertAll(); + } + + @QaseId(334) + @Test(priority = 16) + public void checkInternalTopicsNaming() { + navigateToTopics(); + SoftAssert softly = new SoftAssert(); + topicsList + .setShowInternalRadioButton(true) + .getInternalTopics() + .forEach(topic -> softly.assertTrue(topic.getName().startsWith("_"), + String.format("'%s' starts with '_'", topic.getName()))); + softly.assertAll(); + } + + @QaseId(56) + @Test(priority = 17) + public void checkRetentionBytesAccordingToMaxSizeOnDisk() { + navigateToTopics(); + topicsList + .clickAddTopicBtn(); + topicCreateEditForm + .waitUntilScreenReady() + .setTopicName(TOPIC_TO_CHECK_SETTINGS.getName()) + .setNumberOfPartitions(TOPIC_TO_CHECK_SETTINGS.getNumberOfPartitions()) + .setMaxMessageBytes(TOPIC_TO_CHECK_SETTINGS.getMaxMessageBytes()) + .clickSaveTopicBtn(); + topicDetails + .waitUntilScreenReady(); + TOPIC_LIST.add(TOPIC_TO_CHECK_SETTINGS); + topicDetails + .openDetailsTab(SETTINGS); + topicSettingsTab + .waitUntilScreenReady(); + SoftAssert softly = new SoftAssert(); + softly.assertEquals(topicSettingsTab.getValueByKey("retention.bytes"), + TOPIC_TO_CHECK_SETTINGS.getMaxSizeOnDisk().getOptionValue(), "getValueOfKey(retention.bytes)"); + softly.assertEquals(topicSettingsTab.getValueByKey("max.message.bytes"), + TOPIC_TO_CHECK_SETTINGS.getMaxMessageBytes(), "getValueOfKey(max.message.bytes)"); + softly.assertAll(); + TOPIC_TO_CHECK_SETTINGS + .setMaxSizeOnDisk(SIZE_1_GB) + .setMaxMessageBytes("1000056"); + topicDetails + .openDotMenu() + .clickEditSettingsMenu(); + topicCreateEditForm + .waitUntilScreenReady() + .setMaxSizeOnDiskInGB(TOPIC_TO_CHECK_SETTINGS.getMaxSizeOnDisk()) + .setMaxMessageBytes(TOPIC_TO_CHECK_SETTINGS.getMaxMessageBytes()) + .clickSaveTopicBtn(); + topicDetails + .waitUntilScreenReady() + .openDetailsTab(SETTINGS); + topicSettingsTab + .waitUntilScreenReady(); + softly.assertEquals(topicSettingsTab.getValueByKey("retention.bytes"), + TOPIC_TO_CHECK_SETTINGS.getMaxSizeOnDisk().getOptionValue(), "getValueOfKey(retention.bytes)"); + softly.assertEquals(topicSettingsTab.getValueByKey("max.message.bytes"), + TOPIC_TO_CHECK_SETTINGS.getMaxMessageBytes(), "getValueOfKey(max.message.bytes)"); + softly.assertAll(); + } + + @QaseId(247) + @Test(priority = 18) + public void recreateTopicFromTopicProfile() { + Topic topicToRecreate = new Topic() + .setName("topic-to-recreate-" + randomAlphabetic(5)) + .setNumberOfPartitions(1); + navigateToTopics(); + topicsList + .clickAddTopicBtn(); + topicCreateEditForm + .waitUntilScreenReady() + .setTopicName(topicToRecreate.getName()) + .setNumberOfPartitions(topicToRecreate.getNumberOfPartitions()) + .clickSaveTopicBtn(); + topicDetails + .waitUntilScreenReady(); + TOPIC_LIST.add(topicToRecreate); + topicDetails + .openDotMenu() + .clickRecreateTopicMenu(); + Assert.assertTrue(topicDetails.isConfirmationMdlVisible(), "isConfirmationMdlVisible()"); + topicDetails + .clickConfirmBtnMdl(); + Assert.assertTrue(topicDetails.isAlertWithMessageVisible(SUCCESS, + String.format("Topic %s successfully recreated!", topicToRecreate.getName())), + "isAlertWithMessageVisible()"); + } + + @QaseId(8) + @Test(priority = 19) + public void checkCopyTopicPossibility() { + Topic topicToCopy = new Topic() + .setName("topic-to-copy-" + randomAlphabetic(5)) + .setNumberOfPartitions(1); + navigateToTopics(); + topicsList + .getAnyNonInternalTopic() + .selectItem(true) + .clickCopySelectedTopicBtn(); + topicCreateEditForm + .waitUntilScreenReady(); + Assert.assertFalse(topicCreateEditForm.isCreateTopicButtonEnabled(), "isCreateTopicButtonEnabled()"); + topicCreateEditForm + .setTopicName(topicToCopy.getName()) + .setNumberOfPartitions(topicToCopy.getNumberOfPartitions()) + .clickSaveTopicBtn(); + topicDetails + .waitUntilScreenReady(); + TOPIC_LIST.add(topicToCopy); + SoftAssert softly = new SoftAssert(); + softly.assertTrue(topicDetails.isAlertWithMessageVisible(SUCCESS, "Topic successfully created."), + "isAlertWithMessageVisible()"); + softly.assertTrue(topicDetails.isTopicHeaderVisible(topicToCopy.getName()), "isTopicHeaderVisible()"); + softly.assertAll(); + } + + @AfterClass(alwaysRun = true) + public void afterClass() { + TOPIC_LIST.forEach(topic -> apiService.deleteTopic(topic.getName())); + } +} diff --git a/kafka-ui-e2e-checks/src/test/resources/manual.xml b/kafka-ui-e2e-checks/src/test/resources/manual.xml index dff467651e..f9ea5e5b0f 100644 --- a/kafka-ui-e2e-checks/src/test/resources/manual.xml +++ b/kafka-ui-e2e-checks/src/test/resources/manual.xml @@ -1,8 +1,8 @@ - + - + diff --git a/kafka-ui-e2e-checks/src/test/resources/qase.xml b/kafka-ui-e2e-checks/src/test/resources/qase.xml index 2b5d023b1a..df31931718 100644 --- a/kafka-ui-e2e-checks/src/test/resources/qase.xml +++ b/kafka-ui-e2e-checks/src/test/resources/qase.xml @@ -1,8 +1,8 @@ - + - + diff --git a/kafka-ui-e2e-checks/src/test/resources/regression.xml b/kafka-ui-e2e-checks/src/test/resources/regression.xml index 01db95d03b..fe102bae3e 100644 --- a/kafka-ui-e2e-checks/src/test/resources/regression.xml +++ b/kafka-ui-e2e-checks/src/test/resources/regression.xml @@ -1,10 +1,10 @@ - + - - - + + + diff --git a/kafka-ui-e2e-checks/src/test/resources/sanity.xml b/kafka-ui-e2e-checks/src/test/resources/sanity.xml index e1c8e8a31f..c6b9b06024 100644 --- a/kafka-ui-e2e-checks/src/test/resources/sanity.xml +++ b/kafka-ui-e2e-checks/src/test/resources/sanity.xml @@ -1,8 +1,8 @@ - + - + diff --git a/kafka-ui-e2e-checks/src/test/resources/smoke.xml b/kafka-ui-e2e-checks/src/test/resources/smoke.xml index e0a8f082e8..ab2929ff34 100644 --- a/kafka-ui-e2e-checks/src/test/resources/smoke.xml +++ b/kafka-ui-e2e-checks/src/test/resources/smoke.xml @@ -1,8 +1,8 @@ - + - + diff --git a/kafka-ui-react-app/index.html b/kafka-ui-react-app/index.html index 33e18ad268..be10fc78a3 100644 --- a/kafka-ui-react-app/index.html +++ b/kafka-ui-react-app/index.html @@ -3,13 +3,6 @@ - - - - @@ -25,6 +18,35 @@ return window.basePath+ "/" + importer; }; + diff --git a/kafka-ui-react-app/public/fonts/Inter-Medium.ttf b/kafka-ui-react-app/public/fonts/Inter-Medium.ttf new file mode 100644 index 0000000000..9a3396fc43 Binary files /dev/null and b/kafka-ui-react-app/public/fonts/Inter-Medium.ttf differ diff --git a/kafka-ui-react-app/public/fonts/Inter-Regular.ttf b/kafka-ui-react-app/public/fonts/Inter-Regular.ttf new file mode 100644 index 0000000000..2c164bb2df Binary files /dev/null and b/kafka-ui-react-app/public/fonts/Inter-Regular.ttf differ diff --git a/kafka-ui-react-app/public/fonts/RobotoMono-Medium.ttf b/kafka-ui-react-app/public/fonts/RobotoMono-Medium.ttf new file mode 100644 index 0000000000..395fabe1e9 Binary files /dev/null and b/kafka-ui-react-app/public/fonts/RobotoMono-Medium.ttf differ diff --git a/kafka-ui-react-app/public/fonts/RobotoMono-Regular.ttf b/kafka-ui-react-app/public/fonts/RobotoMono-Regular.ttf new file mode 100644 index 0000000000..2ab8f34a5b Binary files /dev/null and b/kafka-ui-react-app/public/fonts/RobotoMono-Regular.ttf differ diff --git a/kafka-ui-react-app/src/components/Dashboard/Dashboard.tsx b/kafka-ui-react-app/src/components/Dashboard/Dashboard.tsx index 46c35d5079..7eab4c1d2f 100644 --- a/kafka-ui-react-app/src/components/Dashboard/Dashboard.tsx +++ b/kafka-ui-react-app/src/components/Dashboard/Dashboard.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import PageHeading from 'components/common/PageHeading/PageHeading'; import * as Metrics from 'components/common/Metrics'; import { Tag } from 'components/common/Tag/Tag.styled'; @@ -11,6 +11,7 @@ import useBoolean from 'lib/hooks/useBoolean'; import { Button } from 'components/common/Button/Button'; import { clusterNewConfigPath } from 'lib/paths'; import { GlobalSettingsContext } from 'components/contexts/GlobalSettingsContext'; +import { useNavigate } from 'react-router-dom'; import * as S from './Dashboard.styled'; import ClusterName from './ClusterName'; @@ -20,7 +21,7 @@ const Dashboard: React.FC = () => { const clusters = useClusters(); const { value: showOfflineOnly, toggle } = useBoolean(false); const appInfo = React.useContext(GlobalSettingsContext); - + const navigate = useNavigate(); const config = React.useMemo(() => { const clusterList = clusters.data || []; const offlineClusters = clusterList.filter( @@ -55,6 +56,12 @@ const Dashboard: React.FC = () => { return initialColumns; }, []); + useEffect(() => { + if (appInfo.hasDynamicConfig && !clusters.data) { + navigate(clusterNewConfigPath); + } + }, [clusters, appInfo.hasDynamicConfig]); + return ( <> diff --git a/kafka-ui-react-app/src/components/Dashboard/__test__/Dashboard.spec.tsx b/kafka-ui-react-app/src/components/Dashboard/__test__/Dashboard.spec.tsx new file mode 100644 index 0000000000..e9141e980e --- /dev/null +++ b/kafka-ui-react-app/src/components/Dashboard/__test__/Dashboard.spec.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { useClusters } from 'lib/hooks/api/clusters'; +import Dashboard from 'components/Dashboard/Dashboard'; +import { Cluster, ServerStatus } from 'generated-sources'; +import { render } from 'lib/testHelpers'; + +interface DataType { + data: Cluster[] | undefined; +} +jest.mock('lib/hooks/api/clusters'); +const mockedNavigate = jest.fn(); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: () => mockedNavigate, +})); +describe('Dashboard component', () => { + const renderComponent = (hasDynamicConfig: boolean, data: DataType) => { + const useClustersMock = useClusters as jest.Mock; + useClustersMock.mockReturnValue(data); + render(, { + globalSettings: { hasDynamicConfig }, + }); + }; + it('redirects to new cluster configuration page if there are no clusters and dynamic config is enabled', async () => { + await renderComponent(true, { data: undefined }); + + expect(mockedNavigate).toHaveBeenCalled(); + }); + + it('should not navigate to new cluster config page when there are clusters', async () => { + await renderComponent(true, { + data: [{ name: 'Cluster 1', status: ServerStatus.ONLINE }], + }); + + expect(mockedNavigate).not.toHaveBeenCalled(); + }); + + it('should not navigate to new cluster config page when there are no clusters and hasDynamicConfig is false', async () => { + await renderComponent(false, { + data: [], + }); + + expect(mockedNavigate).not.toHaveBeenCalled(); + }); +}); diff --git a/kafka-ui-react-app/src/components/Schemas/Edit/Form.tsx b/kafka-ui-react-app/src/components/Schemas/Edit/Form.tsx index 9ce7f280f4..2fce1ad7d7 100644 --- a/kafka-ui-react-app/src/components/Schemas/Edit/Form.tsx +++ b/kafka-ui-react-app/src/components/Schemas/Edit/Form.tsx @@ -10,6 +10,7 @@ import { clusterSchemasPath, ClusterSubjectParam, } from 'lib/paths'; +import yup from 'lib/yupExtended'; import { NewSchemaSubjectRaw } from 'redux/interfaces'; import Editor from 'components/common/Editor/Editor'; import Select from 'components/common/Select/Select'; @@ -28,6 +29,9 @@ import { import PageLoader from 'components/common/PageLoader/PageLoader'; import { schemasApiClient } from 'lib/api'; import { showServerError } from 'lib/errorHandling'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { FormError } from 'components/common/Input/Input.styled'; +import { ErrorMessage } from '@hookform/error-message'; import * as S from './Edit.styled'; @@ -47,8 +51,16 @@ const Form: React.FC = () => { : JSON.stringify(JSON.parse(schema?.schema || '{}'), null, '\t'); }, [schema]); + const validationSchema = () => + yup.object().shape({ + newSchema: + schema?.schemaType === SchemaType.PROTOBUF + ? yup.string().required().isEnum('Schema syntax is not valid') + : yup.string().required().isJsonObject('Schema syntax is not valid'), + }); const methods = useForm({ mode: 'onChange', + resolver: yupResolver(validationSchema()), defaultValues: { schemaType: schema?.schemaType, compatibilityLevel: @@ -58,11 +70,10 @@ const Form: React.FC = () => { }); const { - formState: { isDirty, isSubmitting, dirtyFields }, + formState: { isDirty, isSubmitting, dirtyFields, errors }, control, handleSubmit, } = methods; - const onSubmit = async (props: NewSchemaSubjectRaw) => { if (!schema) return; @@ -191,11 +202,14 @@ const Form: React.FC = () => { )} /> + + + diff --git a/kafka-ui-react-app/src/components/Topics/Topic/ConsumerGroups/TopicConsumerGroups.styled.ts b/kafka-ui-react-app/src/components/Topics/Topic/ConsumerGroups/TopicConsumerGroups.styled.ts new file mode 100644 index 0000000000..77768dc998 --- /dev/null +++ b/kafka-ui-react-app/src/components/Topics/Topic/ConsumerGroups/TopicConsumerGroups.styled.ts @@ -0,0 +1,6 @@ +import styled from 'styled-components'; + +export const SearchWrapper = styled.div` + margin: 10px; + width: 21%; +`; diff --git a/kafka-ui-react-app/src/components/Topics/Topic/ConsumerGroups/TopicConsumerGroups.tsx b/kafka-ui-react-app/src/components/Topics/Topic/ConsumerGroups/TopicConsumerGroups.tsx index 69948fd66d..173c28c76e 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/ConsumerGroups/TopicConsumerGroups.tsx +++ b/kafka-ui-react-app/src/components/Topics/Topic/ConsumerGroups/TopicConsumerGroups.tsx @@ -5,14 +5,27 @@ import useAppParams from 'lib/hooks/useAppParams'; import { useTopicConsumerGroups } from 'lib/hooks/api/topics'; import { ColumnDef } from '@tanstack/react-table'; import Table, { LinkCell, TagCell } from 'components/common/NewTable'; +import Search from 'components/common/Search/Search'; + +import * as S from './TopicConsumerGroups.styled'; const TopicConsumerGroups: React.FC = () => { + const [keyword, setKeyword] = React.useState(''); const { clusterName, topicName } = useAppParams(); - const { data: consumerGroups = [] } = useTopicConsumerGroups({ + const { data = [] } = useTopicConsumerGroups({ clusterName, topicName, }); + + const consumerGroups = React.useMemo( + () => + data.filter( + (item) => item.groupId.toLocaleLowerCase().indexOf(keyword) > -1 + ), + [data, keyword] + ); + const columns = React.useMemo[]>( () => [ { @@ -61,12 +74,21 @@ const TopicConsumerGroups: React.FC = () => { [] ); return ( - + <> + + + +
+ ); }; diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/Filters.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/Filters.tsx index f9fa3401fc..b3f355f569 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/Filters.tsx +++ b/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/Filters.tsx @@ -53,11 +53,13 @@ export interface FiltersProps { phaseMessage?: string; meta: TopicMessageConsuming; isFetching: boolean; + messageEventType?: string; addMessage(content: { message: TopicMessage; prepend: boolean }): void; resetMessages(): void; updatePhase(phase: string): void; updateMeta(meta: TopicMessageConsuming): void; setIsFetching(status: boolean): void; + setMessageType(messageType: string): void; } export interface MessageFilters { @@ -80,13 +82,15 @@ export const SeekTypeOptions = [ const Filters: React.FC = ({ phaseMessage, - meta: { elapsedMs, bytesConsumed, messagesConsumed }, + meta: { elapsedMs, bytesConsumed, messagesConsumed, filterApplyErrors }, isFetching, addMessage, resetMessages, updatePhase, updateMeta, setIsFetching, + setMessageType, + messageEventType, }) => { const { clusterName, topicName } = useAppParams(); const location = useLocation(); @@ -231,9 +235,13 @@ const Filters: React.FC = ({ props.seekType = SeekType.TIMESTAMP; } + const isSeekTypeWithSeekTo = + props.seekType === SeekType.TIMESTAMP || + props.seekType === SeekType.OFFSET; + if ( selectedPartitions.length !== partitions.length || - currentSeekType === SeekType.TIMESTAMP + isSeekTypeWithSeekTo ) { // not everything in the partition is selected props.seekTo = selectedPartitions.map(({ value }) => { @@ -355,6 +363,12 @@ const Filters: React.FC = ({ case TopicMessageEventTypeEnum.CONSUMING: if (consuming) updateMeta(consuming); break; + case TopicMessageEventTypeEnum.DONE: + if (consuming && type) { + setMessageType(type); + updateMeta(consuming); + } + break; default: } }; @@ -551,6 +565,7 @@ const Filters: React.FC = ({ {seekDirection !== SeekDirection.TAILING && isFetching && phaseMessage} + {!isFetching && messageEventType} @@ -582,6 +597,11 @@ const Filters: React.FC = ({ {messagesConsumed} messages consumed + {!!filterApplyErrors && ( + + {filterApplyErrors} errors + + )} ); diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/FiltersContainer.ts b/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/FiltersContainer.ts index 144672ee60..19dca0184b 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/FiltersContainer.ts +++ b/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/FiltersContainer.ts @@ -6,11 +6,13 @@ import { updateTopicMessagesMeta, updateTopicMessagesPhase, setTopicMessagesFetchingStatus, + setMessageEventType, } from 'redux/reducers/topicMessages/topicMessagesSlice'; import { getTopicMessgesMeta, getTopicMessgesPhase, getIsTopicMessagesFetching, + getIsTopicMessagesType, } from 'redux/reducers/topicMessages/selectors'; import Filters from './Filters'; @@ -19,6 +21,7 @@ const mapStateToProps = (state: RootState) => ({ phaseMessage: getTopicMessgesPhase(state), meta: getTopicMessgesMeta(state), isFetching: getIsTopicMessagesFetching(state), + messageEventType: getIsTopicMessagesType(state), }); const mapDispatchToProps = { @@ -27,6 +30,7 @@ const mapDispatchToProps = { updatePhase: updateTopicMessagesPhase, updateMeta: updateTopicMessagesMeta, setIsFetching: setTopicMessagesFetchingStatus, + setMessageType: setMessageEventType, }; export default connect(mapStateToProps, mapDispatchToProps)(Filters); diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/__tests__/Filters.spec.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/__tests__/Filters.spec.tsx index e248fdeaeb..3e75f11787 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/__tests__/Filters.spec.tsx +++ b/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/__tests__/Filters.spec.tsx @@ -44,13 +44,17 @@ const renderComponent = ( @@ -228,4 +232,17 @@ describe('Filters component', () => { expect(anotherSmartFilterElement).not.toBeInTheDocument(); }); }); + + describe('show errors when get an filterApplyErrors and message event type', () => { + it('show errors', () => { + renderComponent(); + const errors = screen.getByText('10 errors'); + expect(errors).toBeInTheDocument(); + }); + it('message event type when fetching is false ', () => { + renderComponent(); + const messageType = screen.getByText('Done'); + expect(messageType).toBeInTheDocument(); + }); + }); }); diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Messages/Message.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Messages/Message.tsx index 7a9df2c16f..60f09b8293 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Messages/Message.tsx +++ b/kafka-ui-react-app/src/components/Topics/Topic/Messages/Message.tsx @@ -80,19 +80,20 @@ const Message: React.FC = ({ filters?: PreviewFilter[] ) => { if (!filters?.length || !jsonValue) return jsonValue; - const parsedJson = getParsedJson(jsonValue); return ( <> - {filters.map((item) => ( - - {item.field}:{' '} - {JSON.stringify( - JSONPath({ path: item.path, json: parsedJson, wrap: false }) - )} - - ))} + {filters.map((item) => { + return ( +
+ {item.field}:{' '} + {JSON.stringify( + JSONPath({ path: item.path, json: parsedJson, wrap: false }) + )} +
+ ); + })} ); }; diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Messages/MessageContent/MessageContent.styled.ts b/kafka-ui-react-app/src/components/Topics/Topic/Messages/MessageContent/MessageContent.styled.ts index 1c190ba9ca..9eb5e6b062 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Messages/MessageContent/MessageContent.styled.ts +++ b/kafka-ui-react-app/src/components/Topics/Topic/Messages/MessageContent/MessageContent.styled.ts @@ -58,7 +58,7 @@ export const MetadataLabel = styled.p` width: 80px; `; -export const MetadataValue = styled.p` +export const MetadataValue = styled.div` color: ${({ theme }) => theme.topicMetaData.color.value}; font-size: 14px; `; diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Messages/__test__/Message.spec.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Messages/__test__/Message.spec.tsx index c01f4af3d4..c96b395f4c 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Messages/__test__/Message.spec.tsx +++ b/kafka-ui-react-app/src/components/Topics/Topic/Messages/__test__/Message.spec.tsx @@ -1,6 +1,9 @@ import React from 'react'; import { TopicMessage, TopicMessageTimestampTypeEnum } from 'generated-sources'; -import Message, { Props } from 'components/Topics/Topic/Messages/Message'; +import Message, { + PreviewFilter, + Props, +} from 'components/Topics/Topic/Messages/Message'; import { screen } from '@testing-library/react'; import { render } from 'lib/testHelpers'; import userEvent from '@testing-library/user-event'; @@ -8,6 +11,9 @@ import { formatTimestamp } from 'lib/dateTimeHelpers'; const messageContentText = 'messageContentText'; +const keyTest = '{"payload":{"subreddit":"learnprogramming"}}'; +const contentTest = + '{"payload":{"author":"DwaywelayTOP","archived":false,"name":"t3_11jshwd","id":"11jshwd"}}'; jest.mock( 'components/Topics/Topic/Messages/MessageContent/MessageContent', () => () => @@ -28,10 +34,19 @@ describe('Message component', () => { content: '{"data": "test"}', headers: { header: 'test' }, }; - + const mockKeyFilters: PreviewFilter = { + field: 'sub', + path: '$.payload.subreddit', + }; + const mockContentFilters: PreviewFilter = { + field: 'author', + path: '$.payload.author', + }; const renderComponent = ( props: Partial = { message: mockMessage, + keyFilters: [], + contentFilters: [], } ) => render( @@ -39,8 +54,8 @@ describe('Message component', () => {
@@ -88,4 +103,24 @@ describe('Message component', () => { await userEvent.click(messageToggleIcon); expect(screen.getByText(messageContentText)).toBeInTheDocument(); }); + + it('should check if Preview filter showing for key', () => { + const props = { + message: { ...mockMessage, key: keyTest as string }, + keyFilters: [mockKeyFilters], + }; + renderComponent(props); + const keyFiltered = screen.getByText('sub: "learnprogramming"'); + expect(keyFiltered).toBeInTheDocument(); + }); + + it('should check if Preview filter showing for Value', () => { + const props = { + message: { ...mockMessage, content: contentTest as string }, + contentFilters: [mockContentFilters], + }; + renderComponent(props); + const keyFiltered = screen.getByText('author: "DwaywelayTOP"'); + expect(keyFiltered).toBeInTheDocument(); + }); }); diff --git a/kafka-ui-react-app/src/components/contexts/GlobalSettingsContext.tsx b/kafka-ui-react-app/src/components/contexts/GlobalSettingsContext.tsx index 4de05307b1..563fb175f3 100644 --- a/kafka-ui-react-app/src/components/contexts/GlobalSettingsContext.tsx +++ b/kafka-ui-react-app/src/components/contexts/GlobalSettingsContext.tsx @@ -2,7 +2,7 @@ import { useAppInfo } from 'lib/hooks/api/appConfig'; import React from 'react'; import { ApplicationInfoEnabledFeaturesEnum } from 'generated-sources'; -interface GlobalSettingsContextProps { +export interface GlobalSettingsContextProps { hasDynamicConfig: boolean; } diff --git a/kafka-ui-react-app/src/lib/__test__/yupExtended.spec.ts b/kafka-ui-react-app/src/lib/__test__/yupExtended.spec.ts index bd43dd3f72..8100b9a326 100644 --- a/kafka-ui-react-app/src/lib/__test__/yupExtended.spec.ts +++ b/kafka-ui-react-app/src/lib/__test__/yupExtended.spec.ts @@ -1,5 +1,19 @@ -import { isValidJsonObject } from 'lib/yupExtended'; +import { isValidEnum, isValidJsonObject } from 'lib/yupExtended'; +const invalidEnum = ` +ennum SchemType { + AVRO = 0; + JSON = 1; + PROTOBUF = 3; +} +`; +const validEnum = ` +enum SchemType { + AVRO = 0; + JSON = 1; + PROTOBUF = 3; +} +`; describe('yup extended', () => { describe('isValidJsonObject', () => { it('returns false for no value', () => { @@ -21,4 +35,21 @@ describe('yup extended', () => { expect(isValidJsonObject('{ "foo": "bar" }')).toBeTruthy(); }); }); + + describe('isValidEnum', () => { + it('returns false for invalid enum', () => { + expect(isValidEnum(invalidEnum)).toBeFalsy(); + }); + it('returns false for no value', () => { + expect(isValidEnum()).toBeFalsy(); + }); + it('returns true should trim value', () => { + expect( + isValidEnum(` enum SchemType {AVRO = 0; PROTOBUF = 3;} `) + ).toBeTruthy(); + }); + it('returns true for valid enum', () => { + expect(isValidEnum(validEnum)).toBeTruthy(); + }); + }); }); diff --git a/kafka-ui-react-app/src/lib/hooks/api/topics.ts b/kafka-ui-react-app/src/lib/hooks/api/topics.ts index 23e6d65ce3..f71299f19b 100644 --- a/kafka-ui-react-app/src/lib/hooks/api/topics.ts +++ b/kafka-ui-react-app/src/lib/hooks/api/topics.ts @@ -314,9 +314,6 @@ export function useAnalyzeTopic(props: GetTopicDetailsRequest) { const client = useQueryClient(); return useMutation(() => api.analyzeTopic(props), { onSuccess: () => { - showSuccessAlert({ - message: `Topic analysis successfully started`, - }); client.invalidateQueries(topicKeys.statistics(props)); }, }); diff --git a/kafka-ui-react-app/src/lib/testHelpers.tsx b/kafka-ui-react-app/src/lib/testHelpers.tsx index 508904d146..42539a0aac 100644 --- a/kafka-ui-react-app/src/lib/testHelpers.tsx +++ b/kafka-ui-react-app/src/lib/testHelpers.tsx @@ -26,7 +26,10 @@ import { } from '@tanstack/react-query'; import { ConfirmContextProvider } from 'components/contexts/ConfirmContext'; import ConfirmationModal from 'components/common/ConfirmationModal/ConfirmationModal'; -import { GlobalSettingsContext } from 'components/contexts/GlobalSettingsContext'; +import { + GlobalSettingsContext, + GlobalSettingsContextProps, +} from 'components/contexts/GlobalSettingsContext'; import { UserInfoRolesAccessContext } from 'components/contexts/UserInfoRolesAccessContext'; import { RolesType, modifyRolesData } from './permissions'; @@ -35,6 +38,7 @@ interface CustomRenderOptions extends Omit { preloadedState?: Partial; store?: Store, AnyAction>; initialEntries?: MemoryRouterProps['initialEntries']; + globalSettings?: GlobalSettingsContextProps; userInfo?: { roles?: RolesType; rbacFlag: boolean; @@ -110,6 +114,7 @@ const customRender = ( preloadedState, }), initialEntries, + globalSettings = { hasDynamicConfig: false }, userInfo, ...renderOptions }: CustomRenderOptions = {} @@ -119,7 +124,7 @@ const customRender = ( children, }) => ( - + diff --git a/kafka-ui-react-app/src/lib/yupExtended.ts b/kafka-ui-react-app/src/lib/yupExtended.ts index 9c96e073db..4c662ca822 100644 --- a/kafka-ui-react-app/src/lib/yupExtended.ts +++ b/kafka-ui-react-app/src/lib/yupExtended.ts @@ -9,7 +9,8 @@ declare module 'yup' { TDefault = undefined, TFlags extends yup.Flags = '' > extends yup.Schema { - isJsonObject(): StringSchema; + isJsonObject(message?: string): StringSchema; + isEnum(message?: string): StringSchema; } } @@ -31,15 +32,40 @@ export const isValidJsonObject = (value?: string) => { return false; }; -const isJsonObject = () => { +const isJsonObject = (message?: string) => { return yup.string().test( 'isJsonObject', // eslint-disable-next-line no-template-curly-in-string - '${path} is not JSON object', + message || '${path} is not JSON object', isValidJsonObject ); }; +export const isValidEnum = (value?: string) => { + try { + if (!value) return false; + const trimmedValue = value.trim(); + if ( + trimmedValue.indexOf('enum') === 0 && + trimmedValue.lastIndexOf('}') === trimmedValue.length - 1 + ) { + return true; + } + } catch { + // do nothing + } + return false; +}; + +const isEnum = (message?: string) => { + return yup.string().test( + 'isEnum', + // eslint-disable-next-line no-template-curly-in-string + message || '${path} is not Enum object', + isValidEnum + ); +}; + /** * due to yup rerunning all the object validiation during any render, * it makes sense to cache the async results @@ -62,6 +88,7 @@ export function cacheTest( } yup.addMethod(yup.StringSchema, 'isJsonObject', isJsonObject); +yup.addMethod(yup.StringSchema, 'isEnum', isEnum); export const topicFormValidationSchema = yup.object().shape({ name: yup diff --git a/kafka-ui-react-app/src/redux/interfaces/topic.ts b/kafka-ui-react-app/src/redux/interfaces/topic.ts index 9f667e135e..153002240a 100644 --- a/kafka-ui-react-app/src/redux/interfaces/topic.ts +++ b/kafka-ui-react-app/src/redux/interfaces/topic.ts @@ -56,5 +56,6 @@ export interface TopicMessagesState { messages: TopicMessage[]; phase?: string; meta: TopicMessageConsuming; + messageEventType?: string; isFetching: boolean; } diff --git a/kafka-ui-react-app/src/redux/reducers/topicMessages/selectors.ts b/kafka-ui-react-app/src/redux/reducers/topicMessages/selectors.ts index 03adca8e42..b2636cdf2a 100644 --- a/kafka-ui-react-app/src/redux/reducers/topicMessages/selectors.ts +++ b/kafka-ui-react-app/src/redux/reducers/topicMessages/selectors.ts @@ -23,3 +23,8 @@ export const getIsTopicMessagesFetching = createSelector( topicMessagesState, ({ isFetching }) => isFetching ); + +export const getIsTopicMessagesType = createSelector( + topicMessagesState, + ({ messageEventType }) => messageEventType +); diff --git a/kafka-ui-react-app/src/redux/reducers/topicMessages/topicMessagesSlice.ts b/kafka-ui-react-app/src/redux/reducers/topicMessages/topicMessagesSlice.ts index 846cbd0c97..530a378114 100644 --- a/kafka-ui-react-app/src/redux/reducers/topicMessages/topicMessagesSlice.ts +++ b/kafka-ui-react-app/src/redux/reducers/topicMessages/topicMessagesSlice.ts @@ -10,6 +10,7 @@ export const initialState: TopicMessagesState = { messagesConsumed: 0, isCancelled: false, }, + messageEventType: '', isFetching: false, }; @@ -37,6 +38,10 @@ const topicMessagesSlice = createSlice({ setTopicMessagesFetchingStatus: (state, action) => { state.isFetching = action.payload; }, + + setMessageEventType: (state, action) => { + state.messageEventType = action.payload; + }, }, }); @@ -46,6 +51,7 @@ export const { updateTopicMessagesPhase, updateTopicMessagesMeta, setTopicMessagesFetchingStatus, + setMessageEventType, } = topicMessagesSlice.actions; export default topicMessagesSlice.reducer; diff --git a/pom.xml b/pom.xml index 3281ff183e..a82dc72391 100644 --- a/pom.xml +++ b/pom.xml @@ -30,17 +30,13 @@ 3.1.0 3.0.13 2.14.0 - 0.2.4 3.3.1 - 4.1.85.Final 1.4.2.Final 1.18.24 3.21.9 - 1.1.0 2.13.9 - 1.33 - 2.7.5 - 5.7.5 + 2.0 + 3.0.5 1.0.0 0.1.15 0.1.23 @@ -62,9 +58,8 @@ 3.10.1 3.2.0 2.22.2 - 4.3.0 + 6.5.0 1.2.32 - 1.6.0 @@ -111,20 +106,6 @@ pom import
- - org.springframework.security - spring-security-bom - ${spring-security.version} - pom - import - - - io.netty - netty-bom - ${netty.version} - pom - import - com.fasterxml.jackson jackson-bom @@ -147,11 +128,6 @@ protobuf-java ${protobuf-java.version} - - io.projectreactor.netty - reactor-netty-http - ${reactor-netty.version} - org.junit junit-bom