From 46eff34e69d1b3e2a73d568d06e78365a0c3b07b Mon Sep 17 00:00:00 2001 From: Wenjun Ruan Date: Thu, 27 Jun 2024 16:04:03 +0800 Subject: [PATCH] [Fix-16224] Add Shell using file E2E case (#16220) * Add Shell E2E case * Add shell using resource file e2e case * Upgrade checkout from v2 to v4 * Change interval to 500ms * Upgrade actions/upload-artifact --------- Co-authored-by: xiangzihao <460888207@qq.com> --- .github/workflows/api-test.yml | 12 +- .github/workflows/backend.yml | 12 +- .github/workflows/docs.yml | 10 +- .github/workflows/e2e-k8s.yml | 4 +- .github/workflows/e2e.yml | 20 +- .github/workflows/frontend.yml | 6 +- .github/workflows/issue-robot.yml | 2 +- .github/workflows/owasp-dependency-check.yaml | 4 +- .github/workflows/publish-docker.yaml | 2 +- .github/workflows/publish-helm-chart.yaml | 2 +- .github/workflows/unit-test.yml | 4 +- .../api/controller/ResourcesController.java | 10 + .../cases/ClickhouseDataSourceE2ETest.java | 3 +- .../e2e/cases/FileManageE2ETest.java | 5 +- .../e2e/cases/HiveDataSourceE2ETest.java | 3 +- .../e2e/cases/MysqlDataSourceE2ETest.java | 3 +- .../e2e/cases/PostgresDataSourceE2ETest.java | 3 +- .../e2e/cases/SqlServerDataSourceE2ETest.java | 3 +- .../e2e/cases/UserE2ETest.java | 3 +- .../e2e/cases/WorkerGroupE2ETest.java | 3 +- .../e2e/cases/WorkflowE2ETest.java | 3 +- .../e2e/cases/WorkflowHttpTaskE2ETest.java | 3 +- .../e2e/cases/WorkflowJavaTaskE2ETest.java | 3 +- .../e2e/cases/WorkflowSwitchE2ETest.java | 4 +- .../e2e/cases/tasks/ShellTaskE2ETest.java | 260 ++++++++++++++++++ .../cases/workflow/BaseWorkflowE2ETest.java | 219 +++++++++++++++ .../e2e/models/tenant/BootstrapTenant.java | 31 +++ .../e2e/models/tenant/DefaultTenant.java | 30 ++ .../e2e/models/tenant/ITenant.java | 26 ++ .../e2e/models/users/AdminUser.java | 62 +++++ .../e2e/models/users/IUser.java | 35 +++ .../dolphinscheduler/e2e/pages/LoginPage.java | 13 +- .../e2e/pages/common/CodeEditor.java | 5 +- .../e2e/pages/common/HttpInput.java | 3 +- .../e2e/pages/common/NavBarPage.java | 13 +- .../e2e/pages/datasource/DataSourcePage.java | 5 +- .../e2e/pages/project/ProjectDetailPage.java | 10 + .../e2e/pages/project/ProjectPage.java | 30 +- .../project/workflow/TaskInstanceTab.java | 25 +- .../pages/project/workflow/WorkflowForm.java | 3 +- .../project/workflow/WorkflowInstanceTab.java | 8 + .../project/workflow/WorkflowRunDialog.java | 3 +- .../workflow/task/SubWorkflowTaskForm.java | 5 +- .../project/workflow/task/SwitchTaskForm.java | 5 +- .../project/workflow/task/TaskNodeForm.java | 49 +++- .../e2e/pages/resource/FileManagePage.java | 95 ++++--- .../e2e/pages/resource/ResourcePage.java | 10 +- .../e2e/pages/security/EnvironmentPage.java | 5 +- .../e2e/pages/security/SecurityPage.java | 34 +-- .../e2e/pages/security/TenantPage.java | 64 ++++- .../e2e/pages/security/TokenPage.java | 11 +- .../e2e/pages/security/UserPage.java | 20 +- .../e2e/core/DolphinSchedulerExtension.java | 3 +- .../e2e/core/WebDriverHolder.java | 34 +++ .../e2e/core/WebDriverWaitFactory.java | 45 +++ .../spi/enums/ResourceType.java | 2 +- .../components/node/fields/use-resources.ts | 1 + .../projects/task/instance/batch-task.tsx | 1 + 58 files changed, 1109 insertions(+), 183 deletions(-) create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/tasks/ShellTaskE2ETest.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/workflow/BaseWorkflowE2ETest.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/BootstrapTenant.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/DefaultTenant.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/ITenant.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/users/AdminUser.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/users/IUser.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/WebDriverHolder.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/WebDriverWaitFactory.java diff --git a/.github/workflows/api-test.yml b/.github/workflows/api-test.yml index fd39bd0977..b7a1aa4303 100644 --- a/.github/workflows/api-test.yml +++ b/.github/workflows/api-test.yml @@ -35,7 +35,7 @@ jobs: outputs: not-ignore: ${{ steps.filter.outputs.not-ignore }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: dorny/paths-filter@b2feaf19c27470162a626bd6fa8438ae5b263721 id: filter with: @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Sanity Check @@ -73,7 +73,7 @@ jobs: run: | docker save apache/dolphinscheduler-standalone-server:ci -o /tmp/standalone-image.tar \ && du -sh /tmp/standalone-image.tar - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 name: Upload Docker Images with: name: standalone-image @@ -104,7 +104,7 @@ jobs: env: RECORDING_PATH: /tmp/recording-${{ matrix.case.name }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Cache local Maven repository @@ -113,7 +113,7 @@ jobs: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-api-test restore-keys: ${{ runner.os }}-maven- - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 name: Download Docker Images with: name: standalone-image @@ -127,7 +127,7 @@ jobs: -DfailIfNoTests=false \ -Dspotless.skip=false \ -Dtest=${{ matrix.case.class }} test - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: always() name: Upload Recording with: diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index 37fb1bcd7e..8e83cd9792 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -44,7 +44,7 @@ jobs: not-ignore: ${{ steps.filter.outputs.not-ignore }} db-schema: ${{ steps.filter.outputs.db-schema }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: dorny/paths-filter@b2feaf19c27470162a626bd6fa8438ae5b263721 id: filter with: @@ -63,7 +63,7 @@ jobs: java: [ '8', '11' ] timeout-minutes: 30 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Set up JDK ${{ matrix.java }} @@ -91,7 +91,7 @@ jobs: -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 - name: Check dependency license run: tools/dependencies/check-LICENSE.sh - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: ${{ matrix.java == '8' }} name: Upload Binary Package with: @@ -115,10 +115,10 @@ jobs: - name: cluster-test-postgresql-with-postgresql-registry script: .github/workflows/cluster-test/postgresql_with_postgresql_registry/start-job.sh steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 name: Download Binary Package with: # Only run cluster test on jdk8 @@ -165,7 +165,7 @@ jobs: mkdir -p dolphinscheduler/dev dolphinscheduler/${{ matrix.version }} curl -sSf https://atlasgo.sh | sh - name: Download Tarball - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: binary-package-8 path: dolphinscheduler/dev diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 591bb0a65b..81eb7f2073 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -30,7 +30,7 @@ jobs: timeout-minutes: 10 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Style Check run: ./mvnw spotless:check img-check: @@ -40,7 +40,7 @@ jobs: run: working-directory: docs steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python 3.9 uses: actions/setup-python@v2 with: @@ -54,7 +54,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: sudo npm install -g markdown-link-check@3.11.2 - run: sudo apt install plocate -y # NOTE: Change command from `find . -name "*.md"` to `find . -not -path "*/node_modules/*" -not -path "*/.tox/*" -name "*.md"` @@ -70,7 +70,7 @@ jobs: outputs: helm-doc: ${{ steps.filter.outputs.helm-doc }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: dorny/paths-filter@b2feaf19c27470162a626bd6fa8438ae5b263721 id: filter with: @@ -84,7 +84,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Generating helm-doc diff --git a/.github/workflows/e2e-k8s.yml b/.github/workflows/e2e-k8s.yml index fb402b3c79..351aea8802 100644 --- a/.github/workflows/e2e-k8s.yml +++ b/.github/workflows/e2e-k8s.yml @@ -35,7 +35,7 @@ jobs: outputs: not-ignore: ${{ steps.filter.outputs.not-ignore }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: dorny/paths-filter@b2feaf19c27470162a626bd6fa8438ae5b263721 id: filter with: @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Build Image diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 5601dbbb3f..d9a3cd795e 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -35,7 +35,7 @@ jobs: outputs: not-ignore: ${{ steps.filter.outputs.not-ignore }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: dorny/paths-filter@b2feaf19c27470162a626bd6fa8438ae5b263721 id: filter with: @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Sanity Check @@ -74,7 +74,7 @@ jobs: run: | docker save apache/dolphinscheduler-standalone-server:ci -o /tmp/standalone-image.tar \ && du -sh /tmp/standalone-image.tar - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 name: Upload Docker Images with: name: standalone-image @@ -120,10 +120,12 @@ jobs: class: org.apache.dolphinscheduler.e2e.cases.ClickhouseDataSourceE2ETest - name: PostgresDataSource class: org.apache.dolphinscheduler.e2e.cases.PostgresDataSourceE2ETest + - name: ShellTaskE2ETest + class: org.apache.dolphinscheduler.e2e.cases.tasks.ShellTaskE2ETest env: RECORDING_PATH: /tmp/recording-${{ matrix.case.name }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Cache local Maven repository @@ -132,7 +134,7 @@ jobs: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-e2e restore-keys: ${{ runner.os }}-maven- - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 name: Download Docker Images with: name: standalone-image @@ -145,7 +147,7 @@ jobs: ./mvnw -B -f dolphinscheduler-e2e/pom.xml -am \ -DfailIfNoTests=false \ -Dtest=${{ matrix.case.class }} test - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: always() name: Upload Recording with: @@ -167,7 +169,7 @@ jobs: env: RECORDING_PATH: /tmp/recording-${{ matrix.case.name }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Cache local Maven repository @@ -176,7 +178,7 @@ jobs: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-e2e restore-keys: ${{ runner.os }}-maven- - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 name: Download Docker Images with: name: standalone-image @@ -189,7 +191,7 @@ jobs: ./mvnw -B -f dolphinscheduler-e2e/pom.xml -am \ -DfailIfNoTests=false \ -Dtest=${{ matrix.case.class }} test - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: always() name: Upload Recording with: diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 502d669b66..87d178185a 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -41,7 +41,7 @@ jobs: outputs: not-ignore: ${{ steps.filter.outputs.not-ignore }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: dorny/paths-filter@b2feaf19c27470162a626bd6fa8438ae5b263721 id: filter with: @@ -58,7 +58,7 @@ jobs: matrix: os: [ ubuntu-latest, macos-latest ] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - if: matrix.os == 'ubuntu-latest' @@ -82,7 +82,7 @@ jobs: needs: [ build, paths-filter ] if: always() steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Status run: | if [[ ${{ needs.paths-filter.outputs.not-ignore }} == 'false' && ${{ github.event_name }} == 'pull_request' ]]; then diff --git a/.github/workflows/issue-robot.yml b/.github/workflows/issue-robot.yml index ab00b34681..06a363d11f 100644 --- a/.github/workflows/issue-robot.yml +++ b/.github/workflows/issue-robot.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout ${{ github.ref }}" - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: persist-credentials: false submodules: true diff --git a/.github/workflows/owasp-dependency-check.yaml b/.github/workflows/owasp-dependency-check.yaml index 54e51aafed..b99486f298 100644 --- a/.github/workflows/owasp-dependency-check.yaml +++ b/.github/workflows/owasp-dependency-check.yaml @@ -31,7 +31,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Set up JDK 8 @@ -42,7 +42,7 @@ jobs: - name: Run OWASP Dependency Check run: ./mvnw -B clean install verify dependency-check:check -DskipDepCheck=false -Dmaven.test.skip=true -Dspotless.skip=true - name: Upload report - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ cancelled() || failure() }} continue-on-error: true with: diff --git a/.github/workflows/publish-docker.yaml b/.github/workflows/publish-docker.yaml index 06aa8c6950..859e22f25c 100644 --- a/.github/workflows/publish-docker.yaml +++ b/.github/workflows/publish-docker.yaml @@ -33,7 +33,7 @@ jobs: packages: write timeout-minutes: 30 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Cache local Maven repository uses: actions/cache@v3 with: diff --git a/.github/workflows/publish-helm-chart.yaml b/.github/workflows/publish-helm-chart.yaml index e383373692..247a55f4cc 100644 --- a/.github/workflows/publish-helm-chart.yaml +++ b/.github/workflows/publish-helm-chart.yaml @@ -33,7 +33,7 @@ jobs: packages: write timeout-minutes: 30 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set environment variables run: | if [[ ${{ github.event_name }} == "release" ]]; then diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index a7e78a11f7..d0c88b9ca6 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -40,7 +40,7 @@ jobs: outputs: not-ignore: ${{ steps.filter.outputs.not-ignore }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: dorny/paths-filter@b2feaf19c27470162a626bd6fa8438ae5b263721 id: filter with: @@ -57,7 +57,7 @@ jobs: java: ['8', '11'] timeout-minutes: 45 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Sanity Check diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ResourcesController.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ResourcesController.java index 0c9a34ee53..03eb42c5d6 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ResourcesController.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ResourcesController.java @@ -92,6 +92,16 @@ public class ResourcesController extends BaseController { @Autowired private ResourcesService resourceService; + @Operation(summary = "queryResourceList", description = "QUERY_RESOURCE_LIST_NOTES") + @Parameter(name = "type", description = "RESOURCE_TYPE", required = true, schema = @Schema(implementation = ResourceType.class)) + @GetMapping(value = "/list") + @ResponseStatus(HttpStatus.OK) + @ApiException(QUERY_RESOURCES_LIST_ERROR) + public Result> queryResourceList(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser, + @RequestParam(value = "type") ResourceType type) { + return Result.success(resourceService.queryResourceFiles(loginUser, type)); + } + @Operation(summary = "createDirectory", description = "CREATE_RESOURCE_NOTES") @Parameters({ @Parameter(name = "type", description = "RESOURCE_TYPE", required = true, schema = @Schema(implementation = ResourceType.class)), diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/ClickhouseDataSourceE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/ClickhouseDataSourceE2ETest.java index e150e73e98..412b5f6a8a 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/ClickhouseDataSourceE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/ClickhouseDataSourceE2ETest.java @@ -23,6 +23,7 @@ package org.apache.dolphinscheduler.e2e.cases; import static org.assertj.core.api.Assertions.assertThat; import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.LoginPage; import org.apache.dolphinscheduler.e2e.pages.datasource.DataSourcePage; @@ -82,7 +83,7 @@ public class ClickhouseDataSourceE2ETest { page.createDataSource(dataSourceType, dataSourceName, dataSourceDescription, ip, port, userName, pgPassword, database, jdbcParams); - new WebDriverWait(page.driver(), Duration.ofSeconds(20)).until(ExpectedConditions.invisibilityOfElementLocated( + WebDriverWaitFactory.createWebDriverWait(page.driver()).until(ExpectedConditions.invisibilityOfElementLocated( new By.ByClassName("dialog-create-data-source"))); Awaitility.await().untilAsserted(() -> assertThat(page.dataSourceItemsList()) diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java index 1bfa997f85..ad041b9ac4 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java @@ -24,6 +24,7 @@ import static org.assertj.core.api.Assertions.assertThat; import org.apache.dolphinscheduler.e2e.core.Constants; import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.LoginPage; import org.apache.dolphinscheduler.e2e.pages.resource.FileManagePage; import org.apache.dolphinscheduler.e2e.pages.resource.ResourcePage; @@ -98,7 +99,7 @@ public class FileManageE2ETest { UserPage userPage = tenantPage.goToNav(SecurityPage.class) .goToTab(UserPage.class); - new WebDriverWait(userPage.driver(), Duration.ofSeconds(20)).until(ExpectedConditions.visibilityOfElementLocated( + WebDriverWaitFactory.createWebDriverWait(userPage.driver()).until(ExpectedConditions.visibilityOfElementLocated( new By.ByClassName("name"))); userPage.update(user, user, email, phone, tenant) @@ -285,7 +286,7 @@ public class FileManageE2ETest { page.uploadFile(testUnder1GBFilePath.toFile().getAbsolutePath()); - new WebDriverWait(browser, Duration.ofSeconds(20)).until(ExpectedConditions.invisibilityOfElementLocated(By.id("fileUpdateDialog"))); + WebDriverWaitFactory.createWebDriverWait(browser).until(ExpectedConditions.invisibilityOfElementLocated(By.id("fileUpdateDialog"))); Awaitility.await().untilAsserted(() -> { assertThat(page.fileList()) diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/HiveDataSourceE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/HiveDataSourceE2ETest.java index 9b6e661f52..3726ec1acd 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/HiveDataSourceE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/HiveDataSourceE2ETest.java @@ -23,6 +23,7 @@ package org.apache.dolphinscheduler.e2e.cases; import static org.assertj.core.api.Assertions.assertThat; import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.LoginPage; import org.apache.dolphinscheduler.e2e.pages.datasource.DataSourcePage; @@ -82,7 +83,7 @@ public class HiveDataSourceE2ETest { page.createDataSource(dataSourceType, dataSourceName, dataSourceDescription, ip, port, userName, hivePassword, database, jdbcParams); - new WebDriverWait(page.driver(), Duration.ofSeconds(20)).until(ExpectedConditions.invisibilityOfElementLocated( + WebDriverWaitFactory.createWebDriverWait(page.driver()).until(ExpectedConditions.invisibilityOfElementLocated( new By.ByClassName("dialog-create-data-source"))); Awaitility.await().untilAsserted(() -> assertThat(page.dataSourceItemsList()) diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/MysqlDataSourceE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/MysqlDataSourceE2ETest.java index 5078f55e35..5c0746a5b5 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/MysqlDataSourceE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/MysqlDataSourceE2ETest.java @@ -23,6 +23,7 @@ package org.apache.dolphinscheduler.e2e.cases; import static org.assertj.core.api.Assertions.assertThat; import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.LoginPage; import org.apache.dolphinscheduler.e2e.pages.datasource.DataSourcePage; @@ -82,7 +83,7 @@ public class MysqlDataSourceE2ETest { page.createDataSource(dataSourceType, dataSourceName, dataSourceDescription, ip, port, userName, mysqlPassword, database, jdbcParams); - new WebDriverWait(page.driver(), Duration.ofSeconds(20)).until(ExpectedConditions.invisibilityOfElementLocated( + WebDriverWaitFactory.createWebDriverWait(page.driver()).until(ExpectedConditions.invisibilityOfElementLocated( new By.ByClassName("dialog-create-data-source"))); Awaitility.await().untilAsserted(() -> assertThat(page.dataSourceItemsList()) diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/PostgresDataSourceE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/PostgresDataSourceE2ETest.java index 647c667741..cbed2b3b8b 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/PostgresDataSourceE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/PostgresDataSourceE2ETest.java @@ -23,6 +23,7 @@ package org.apache.dolphinscheduler.e2e.cases; import static org.assertj.core.api.Assertions.assertThat; import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.LoginPage; import org.apache.dolphinscheduler.e2e.pages.datasource.DataSourcePage; @@ -82,7 +83,7 @@ public class PostgresDataSourceE2ETest { page.createDataSource(dataSourceType, dataSourceName, dataSourceDescription, ip, port, userName, pgPassword, database, jdbcParams); - new WebDriverWait(page.driver(), Duration.ofSeconds(20)).until(ExpectedConditions.invisibilityOfElementLocated( + WebDriverWaitFactory.createWebDriverWait(page.driver()).until(ExpectedConditions.invisibilityOfElementLocated( new By.ByClassName("dialog-create-data-source"))); Awaitility.await().untilAsserted(() -> assertThat(page.dataSourceItemsList()) diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/SqlServerDataSourceE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/SqlServerDataSourceE2ETest.java index 7777b9a441..7f6ee662dd 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/SqlServerDataSourceE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/SqlServerDataSourceE2ETest.java @@ -23,6 +23,7 @@ package org.apache.dolphinscheduler.e2e.cases; import static org.assertj.core.api.Assertions.assertThat; import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.LoginPage; import org.apache.dolphinscheduler.e2e.pages.datasource.DataSourcePage; @@ -82,7 +83,7 @@ public class SqlServerDataSourceE2ETest { page.createDataSource(dataSourceType, dataSourceName, dataSourceDescription, ip, port, userName, pgPassword, database, jdbcParams); - new WebDriverWait(page.driver(), Duration.ofSeconds(20)).until(ExpectedConditions.invisibilityOfElementLocated( + WebDriverWaitFactory.createWebDriverWait(page.driver()).until(ExpectedConditions.invisibilityOfElementLocated( new By.ByClassName("dialog-create-data-source"))); Awaitility.await().untilAsserted(() -> assertThat(page.dataSourceItemsList()) diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UserE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UserE2ETest.java index 3ed263ec0e..150e84b618 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UserE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UserE2ETest.java @@ -23,6 +23,7 @@ package org.apache.dolphinscheduler.e2e.cases; import static org.assertj.core.api.Assertions.assertThat; import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.LoginPage; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage; @@ -119,7 +120,7 @@ class UserE2ETest { void testEditUser() { UserPage page = new UserPage(browser); - new WebDriverWait(browser, Duration.ofSeconds(20)).until(ExpectedConditions.visibilityOfElementLocated( + WebDriverWaitFactory.createWebDriverWait(browser).until(ExpectedConditions.visibilityOfElementLocated( new By.ByClassName("name"))); browser.navigate().refresh(); diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkerGroupE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkerGroupE2ETest.java index b7f2a9474c..be8caf0913 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkerGroupE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkerGroupE2ETest.java @@ -23,6 +23,7 @@ package org.apache.dolphinscheduler.e2e.cases; import static org.assertj.core.api.Assertions.assertThat; import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.LoginPage; import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage; import org.apache.dolphinscheduler.e2e.pages.security.WorkerGroupPage; @@ -59,7 +60,7 @@ class WorkerGroupE2ETest { void testCreateWorkerGroup() { final WorkerGroupPage page = new WorkerGroupPage(browser); - new WebDriverWait(page.driver(), Duration.ofSeconds(20)) + WebDriverWaitFactory.createWebDriverWait(page.driver()) .until(ExpectedConditions.urlContains("/security/worker-group-manage")); page.create(workerGroupName); diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java index 0b97ab02af..bbfcacbceb 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java @@ -20,6 +20,7 @@ package org.apache.dolphinscheduler.e2e.cases; import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.LoginPage; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import org.apache.dolphinscheduler.e2e.pages.project.ProjectDetailPage; @@ -76,7 +77,7 @@ class WorkflowE2ETest { .goToNav(SecurityPage.class) .goToTab(UserPage.class); - new WebDriverWait(userPage.driver(), Duration.ofSeconds(20)).until(ExpectedConditions.visibilityOfElementLocated( + WebDriverWaitFactory.createWebDriverWait(userPage.driver()).until(ExpectedConditions.visibilityOfElementLocated( new By.ByClassName("name"))); userPage.update(user, user, email, phone, tenant) diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowHttpTaskE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowHttpTaskE2ETest.java index 0993e61b81..3f78fd25f7 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowHttpTaskE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowHttpTaskE2ETest.java @@ -20,6 +20,7 @@ package org.apache.dolphinscheduler.e2e.cases; import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.LoginPage; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import org.apache.dolphinscheduler.e2e.pages.project.ProjectDetailPage; @@ -76,7 +77,7 @@ public class WorkflowHttpTaskE2ETest { .goToNav(SecurityPage.class) .goToTab(UserPage.class); - new WebDriverWait(userPage.driver(), Duration.ofSeconds(20)).until(ExpectedConditions.visibilityOfElementLocated( + WebDriverWaitFactory.createWebDriverWait(userPage.driver()).until(ExpectedConditions.visibilityOfElementLocated( new By.ByClassName("name"))); userPage.update(user, user, email, phone, tenant) diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowJavaTaskE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowJavaTaskE2ETest.java index 77c4e554bc..700ec03f43 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowJavaTaskE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowJavaTaskE2ETest.java @@ -20,6 +20,7 @@ package org.apache.dolphinscheduler.e2e.cases; import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.LoginPage; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import org.apache.dolphinscheduler.e2e.pages.project.ProjectDetailPage; @@ -92,7 +93,7 @@ public class WorkflowJavaTaskE2ETest { .goToNav(SecurityPage.class) .goToTab(UserPage.class); - new WebDriverWait(userPage.driver(), Duration.ofSeconds(20)) + WebDriverWaitFactory.createWebDriverWait(userPage.driver()) .until(ExpectedConditions.visibilityOfElementLocated(new By.ByClassName("name"))); userPage.update(user, user, email, phone, tenant) diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowSwitchE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowSwitchE2ETest.java index edf4bc59e2..cee9b52b47 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowSwitchE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowSwitchE2ETest.java @@ -178,8 +178,8 @@ class WorkflowSwitchE2ETest { Awaitility.await().untilAsserted(() -> { assertThat(taskInstances.size()).isEqualTo(3); - assertThat(taskInstances.stream().filter(row -> row.name().contains(ifBranchName)).count()).isEqualTo(1); - assertThat(taskInstances.stream().noneMatch(row -> row.name().contains(elseBranchName))).isTrue(); + assertThat(taskInstances.stream().filter(row -> row.taskInstanceName().contains(ifBranchName)).count()).isEqualTo(1); + assertThat(taskInstances.stream().noneMatch(row -> row.taskInstanceName().contains(elseBranchName))).isTrue(); }); } } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/tasks/ShellTaskE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/tasks/ShellTaskE2ETest.java new file mode 100644 index 0000000000..fb44bc843a --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/tasks/ShellTaskE2ETest.java @@ -0,0 +1,260 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.e2e.cases.tasks; + +import org.apache.dolphinscheduler.e2e.cases.workflow.BaseWorkflowE2ETest; +import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.pages.project.ProjectPage; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.TaskInstanceTab; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowDefinitionTab; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowForm; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowInstanceTab; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.task.ShellTaskForm; +import org.apache.dolphinscheduler.e2e.pages.resource.FileManagePage; +import org.apache.dolphinscheduler.e2e.pages.resource.ResourcePage; +import org.junit.FixMethodOrder; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.runners.MethodSorters; +import org.openqa.selenium.WebElement; +import org.testcontainers.shaded.org.awaitility.Awaitility; +import static org.assertj.core.api.Assertions.assertThat; +import static org.testcontainers.shaded.org.awaitility.Awaitility.await; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@DolphinScheduler(composeFiles = "docker/basic/docker-compose.yaml") +public class ShellTaskE2ETest extends BaseWorkflowE2ETest { + + @Test + void testRunShellTasks_SuccessCase() { + WorkflowDefinitionTab workflowDefinitionPage = + new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName) + .goToTab(WorkflowDefinitionTab.class); + + // todo: use yaml to define the workflow + String workflowName = "SuccessCase"; + String taskName = "ShellSuccess"; + workflowDefinitionPage + .createWorkflow() + .addTask(WorkflowForm.TaskType.SHELL) + .script("echo hello world\n") + .name(taskName) + .submit() + + .submit() + .name(workflowName) + .submit(); + + untilWorkflowDefinitionExist(workflowName); + + workflowDefinitionPage.publish(workflowName); + + runWorkflow(workflowName); + untilWorkflowInstanceExist(workflowName); + WorkflowInstanceTab.Row workflowInstance = untilWorkflowInstanceSuccess(workflowName); + assertThat(workflowInstance.executionTime()).isEqualTo(1); + + TaskInstanceTab.Row taskInstance = untilTaskInstanceSuccess(workflowName, taskName); + assertThat(taskInstance.retryTimes()).isEqualTo(0); + } + + @Test + void testRunShellTasks_WorkflowParamsCase() { + WorkflowDefinitionTab workflowDefinitionPage = + new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName) + .goToTab(WorkflowDefinitionTab.class); + + // todo: use yaml to define the workflow + String workflowName = "WorkflowParamsCase"; + String taskName = "ShellSuccess"; + workflowDefinitionPage + .createWorkflow() + .addTask(WorkflowForm.TaskType.SHELL) + .script("[ \"${name}\" = \"tom\" ] && echo \"success\" || { echo \"failed\"; exit 1; }") + .name(taskName) + .submit() + + .submit() + .name(workflowName) + .addGlobalParam("name", "tom") + .submit(); + + untilWorkflowDefinitionExist(workflowName); + + workflowDefinitionPage.publish(workflowName); + + runWorkflow(workflowName); + untilWorkflowInstanceExist(workflowName); + WorkflowInstanceTab.Row workflowInstance = untilWorkflowInstanceSuccess(workflowName); + assertThat(workflowInstance.executionTime()).isEqualTo(1); + + TaskInstanceTab.Row taskInstance = untilTaskInstanceSuccess(workflowName, taskName); + assertThat(taskInstance.retryTimes()).isEqualTo(0); + } + + @Test + void testRunShellTasks_LocalParamsCase() { + WorkflowDefinitionTab workflowDefinitionPage = + new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName) + .goToTab(WorkflowDefinitionTab.class); + + String workflowName = "LocalParamsCase"; + String taskName = "ShellSuccess"; + workflowDefinitionPage + .createWorkflow() + .addTask(WorkflowForm.TaskType.SHELL) + .script("[ \"${name}\" = \"tom\" ] && echo \"success\" || { echo \"failed\"; exit 1; }") + .name(taskName) + .addParam("name", "tom") + .submit() + + .submit() + .name(workflowName) + .submit(); + + untilWorkflowDefinitionExist(workflowName); + + workflowDefinitionPage.publish(workflowName); + + runWorkflow(workflowName); + untilWorkflowInstanceExist(workflowName); + WorkflowInstanceTab.Row workflowInstance = untilWorkflowInstanceSuccess(workflowName); + assertThat(workflowInstance.executionTime()).isEqualTo(1); + + TaskInstanceTab.Row taskInstance = untilTaskInstanceSuccess(workflowName, taskName); + assertThat(taskInstance.retryTimes()).isEqualTo(0); + } + + @Test + void testRunShellTasks_GlobalParamsOverrideLocalParamsCase() { + WorkflowDefinitionTab workflowDefinitionPage = + new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName) + .goToTab(WorkflowDefinitionTab.class); + + String workflowName = "LocalParamsOverrideWorkflowParamsCase"; + String taskName = "ShellSuccess"; + workflowDefinitionPage + .createWorkflow() + .addTask(WorkflowForm.TaskType.SHELL) + .script("[ \"${name}\" = \"jerry\" ] && echo \"success\" || { echo \"failed\"; exit 1; }") + .name(taskName) + .addParam("name", "tom") + .submit() + + .submit() + .name(workflowName) + .addGlobalParam("name", "jerry") + .submit(); + + untilWorkflowDefinitionExist(workflowName); + + workflowDefinitionPage.publish(workflowName); + + runWorkflow(workflowName); + untilWorkflowInstanceExist(workflowName); + WorkflowInstanceTab.Row workflowInstance = untilWorkflowInstanceSuccess(workflowName); + assertThat(workflowInstance.executionTime()).isEqualTo(1); + + TaskInstanceTab.Row taskInstance = untilTaskInstanceSuccess(workflowName, taskName); + assertThat(taskInstance.retryTimes()).isEqualTo(0); + } + + @Test + void testRunShellTasks_UsingResourceFile() { + String testFileName = "echo"; + new ResourcePage(browser) + .goToNav(ResourcePage.class) + .goToTab(FileManagePage.class) + .createFileUntilSuccess(testFileName, "echo 123"); + + final WorkflowDefinitionTab workflowDefinitionPage = + new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName) + .goToTab(WorkflowDefinitionTab.class); + + String workflowName = "UsingResourceFile"; + String taskName = "ShellSuccess"; + workflowDefinitionPage + .createWorkflow() + .addTask(WorkflowForm.TaskType.SHELL) + .script("cat " + testFileName + ".sh") + .name(taskName) + .selectResource(testFileName) + .submit() + + .submit() + .name(workflowName) + .submit(); + + untilWorkflowDefinitionExist(workflowName); + + workflowDefinitionPage.publish(workflowName); + + runWorkflow(workflowName); + untilWorkflowInstanceExist(workflowName); + WorkflowInstanceTab.Row workflowInstance = untilWorkflowInstanceSuccess(workflowName); + assertThat(workflowInstance.executionTime()).isEqualTo(1); + + TaskInstanceTab.Row taskInstance = untilTaskInstanceSuccess(workflowName, taskName); + assertThat(taskInstance.retryTimes()).isEqualTo(0); + } + + @Test + void testRunShellTasks_FailedCase() { + WorkflowDefinitionTab workflowDefinitionPage = + new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName) + .goToTab(WorkflowDefinitionTab.class); + + String workflowName = "FailedCase"; + String taskName = "ShellFailed"; + workflowDefinitionPage + .createWorkflow() + .addTask(WorkflowForm.TaskType.SHELL) + .script("echo 'I am failed'\n exit1\n") + .name(taskName) + .submit() + + .submit() + .name(workflowName) + .submit(); + + untilWorkflowDefinitionExist(workflowName); + + workflowDefinitionPage.publish(workflowName); + + runWorkflow(workflowName); + untilWorkflowInstanceExist(workflowName); + WorkflowInstanceTab.Row workflowInstance = untilWorkflowInstanceFailed(workflowName); + assertThat(workflowInstance.executionTime()).isEqualTo(1); + + TaskInstanceTab.Row taskInstance = untilTaskInstanceFailed(workflowName, taskName); + assertThat(taskInstance.retryTimes()).isEqualTo(0); + } + +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/workflow/BaseWorkflowE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/workflow/BaseWorkflowE2ETest.java new file mode 100644 index 0000000000..aab2c7c06f --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/workflow/BaseWorkflowE2ETest.java @@ -0,0 +1,219 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.e2e.cases.workflow; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.dolphinscheduler.e2e.core.WebDriverHolder; +import org.apache.dolphinscheduler.e2e.models.tenant.DefaultTenant; +import org.apache.dolphinscheduler.e2e.models.users.AdminUser; +import org.apache.dolphinscheduler.e2e.models.users.IUser; +import org.apache.dolphinscheduler.e2e.pages.LoginPage; +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; +import org.apache.dolphinscheduler.e2e.pages.project.ProjectDetailPage; +import org.apache.dolphinscheduler.e2e.pages.project.ProjectPage; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.TaskInstanceTab; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowDefinitionTab; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowInstanceTab; +import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage; +import org.apache.dolphinscheduler.e2e.pages.security.TenantPage; +import org.apache.dolphinscheduler.e2e.pages.security.UserPage; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.openqa.selenium.remote.RemoteWebDriver; +import static org.assertj.core.api.Assertions.assertThat; +import static org.testcontainers.shaded.org.awaitility.Awaitility.await; + +@Slf4j +public abstract class BaseWorkflowE2ETest { + + protected static String projectName = UUID.randomUUID().toString(); + + protected static final AdminUser adminUser = new AdminUser(); + + protected static RemoteWebDriver browser; + + @BeforeAll + public static void setup() { + browser = WebDriverHolder.getWebDriver(); + + TenantPage tenantPage = new LoginPage(browser) + .login(adminUser) + .goToNav(SecurityPage.class) + .goToTab(TenantPage.class); + + if (tenantPage.tenants().stream().noneMatch(tenant -> tenant.tenantCode().equals(adminUser.getTenant()))) { + tenantPage + .create(adminUser.getTenant()) + .goToNav(SecurityPage.class) + .goToTab(UserPage.class) + .update(adminUser); + } + tenantPage + .goToNav(ProjectPage.class) + .createProjectUntilSuccess(projectName); + } + + protected void untilWorkflowDefinitionExist(String workflowName) { + WorkflowDefinitionTab workflowDefinitionPage = new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName) + .goToTab(WorkflowDefinitionTab.class); + + await().untilAsserted(() -> assertThat(workflowDefinitionPage.workflowList()) + .as("Workflow list should contain newly-created workflow: %s", workflowName) + .anyMatch( + it -> it.getText().contains(workflowName) + )); + } + + protected void runWorkflow(String workflowName) { + final ProjectDetailPage projectPage = new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName); + + projectPage + .goToTab(WorkflowDefinitionTab.class) + .run(workflowName) + .submit(); + + } + + protected WorkflowInstanceTab.Row untilWorkflowInstanceExist(String workflowName) { + final ProjectDetailPage projectPage = new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName); + + return await() + .until(() -> { + browser.navigate().refresh(); + return projectPage + .goToTab(WorkflowInstanceTab.class) + .instances() + .stream() + .filter(it -> it.workflowInstanceName().startsWith(workflowName)) + .findFirst() + .orElse(null); + }, Objects::nonNull); + } + + protected WorkflowInstanceTab.Row untilWorkflowInstanceSuccess(String workflowName) { + final ProjectDetailPage projectPage = new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName); + return await() + .until(() -> { + browser.navigate().refresh(); + return projectPage + .goToTab(WorkflowInstanceTab.class) + .instances() + .stream() + .filter(it -> it.workflowInstanceName().startsWith(workflowName)) + .filter(WorkflowInstanceTab.Row::isSuccess) + .findFirst() + .orElse(null); + }, Objects::nonNull); + } + + protected WorkflowInstanceTab.Row untilWorkflowInstanceFailed(String workflowName) { + final ProjectDetailPage projectPage = new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName); + return await() + .until(() -> { + browser.navigate().refresh(); + List workflowInstances = projectPage + .goToTab(WorkflowInstanceTab.class) + .instances() + .stream() + .filter(it -> it.workflowInstanceName().startsWith(workflowName)) + .filter(WorkflowInstanceTab.Row::isFailed) + .collect(Collectors.toList()); + if (workflowInstances.isEmpty()) { + return null; + } + if (workflowInstances.size() > 1) { + throw new RuntimeException("More than one failed workflow instance found: " + + workflowInstances.stream() + .map(WorkflowInstanceTab.Row::workflowInstanceName).collect(Collectors.joining(", "))); + } + return workflowInstances.get(0); + }, Objects::nonNull); + } + + protected TaskInstanceTab.Row untilTaskInstanceSuccess(String workflowName, String taskName) { + final ProjectDetailPage projectPage = new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName); + return await() + .until(() -> { + browser.navigate().refresh(); + List taskInstances = projectPage + .goToTab(TaskInstanceTab.class) + .instances() + .stream() + .filter(it -> it.taskInstanceName().startsWith(taskName)) + .filter(it -> it.workflowInstanceName().startsWith(workflowName)) + .filter(TaskInstanceTab.Row::isSuccess) + .collect(Collectors.toList()); + + if (taskInstances.isEmpty()) { + return null; + } + if (taskInstances.size() > 1) { + throw new RuntimeException("More than one failed task instance found: " + + taskInstances.stream() + .map(TaskInstanceTab.Row::taskInstanceName).collect(Collectors.joining(", "))); + } + return taskInstances.get(0); + }, Objects::nonNull); + } + + protected TaskInstanceTab.Row untilTaskInstanceFailed(String workflowName, String taskName) { + final ProjectDetailPage projectPage = new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(projectName); + return await() + .until(() -> { + browser.navigate().refresh(); + List taskInstances = projectPage + .goToTab(TaskInstanceTab.class) + .instances() + .stream() + .filter(it -> it.taskInstanceName().startsWith(taskName)) + .filter(it -> it.workflowInstanceName().startsWith(workflowName)) + .filter(TaskInstanceTab.Row::isFailed) + .collect(Collectors.toList()); + + if (taskInstances.isEmpty()) { + return null; + } + if (taskInstances.size() > 1) { + throw new RuntimeException("More than one failed task instance found: " + + taskInstances.stream() + .map(TaskInstanceTab.Row::taskInstanceName).collect(Collectors.joining(", "))); + } + return taskInstances.get(0); + }, Objects::nonNull); + } + +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/BootstrapTenant.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/BootstrapTenant.java new file mode 100644 index 0000000000..15af3197e2 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/BootstrapTenant.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.e2e.models.tenant; + +public class BootstrapTenant implements ITenant { + + @Override + public String getTenantCode() { + return System.getProperty("user.name"); + } + + @Override + public String getDescription() { + return "bootstrap tenant"; + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/DefaultTenant.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/DefaultTenant.java new file mode 100644 index 0000000000..598265fa96 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/DefaultTenant.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.e2e.models.tenant; + +public class DefaultTenant implements ITenant { + @Override + public String getTenantCode() { + return "default"; + } + + @Override + public String getDescription() { + return ""; + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/ITenant.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/ITenant.java new file mode 100644 index 0000000000..641acbf9d7 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/ITenant.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.e2e.models.tenant; + +public interface ITenant { + + String getTenantCode(); + + String getDescription(); + +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/users/AdminUser.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/users/AdminUser.java new file mode 100644 index 0000000000..da23bc26bf --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/users/AdminUser.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.e2e.models.users; + +import lombok.Data; +import org.apache.dolphinscheduler.e2e.models.tenant.BootstrapTenant; +import org.apache.dolphinscheduler.e2e.models.tenant.ITenant; + +@Data +public class AdminUser implements IUser { + + private String userName; + + private String password; + + private String email; + + private String phone; + + private ITenant tenant; + + @Override + public String getUserName() { + return "admin"; + } + + @Override + public String getPassword() { + return "dolphinscheduler123"; + } + + @Override + public String getEmail() { + return "admin@gmail.com"; + } + + @Override + public String getPhone() { + return "15800000000"; + } + + @Override + public String getTenant() { + return new BootstrapTenant().getTenantCode(); + } + +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/users/IUser.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/users/IUser.java new file mode 100644 index 0000000000..740a4b431e --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/users/IUser.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.e2e.models.users; + +import org.apache.dolphinscheduler.e2e.models.tenant.ITenant; + +public interface IUser { + + String getUserName(); + + String getPassword(); + + String getEmail(); + + String getPhone(); + + String getTenant(); + + +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java index cde8c9d778..a77149fac3 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java @@ -19,6 +19,8 @@ package org.apache.dolphinscheduler.e2e.pages; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; +import org.apache.dolphinscheduler.e2e.models.users.IUser; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import org.apache.dolphinscheduler.e2e.pages.security.TenantPage; @@ -59,17 +61,20 @@ public final class LoginPage extends NavBarPage { } @SneakyThrows - public NavBarPage login(String username, String password) { - new WebDriverWait(driver, Duration.ofSeconds(30)).until(ExpectedConditions.elementToBeClickable(buttonSwitchLanguage)); + public NavBarPage login(IUser user) { + return login(user.getUserName(), user.getPassword()); + } + @SneakyThrows + public NavBarPage login(String username, String password) { + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(buttonSwitchLanguage)); buttonSwitchLanguage().click(); inputUsername().sendKeys(username); inputPassword().sendKeys(password); buttonLogin().click(); - new WebDriverWait(driver, Duration.ofSeconds(30)) - .until(ExpectedConditions.urlContains("/home")); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/home")); return new NavBarPage(driver); } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/CodeEditor.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/CodeEditor.java index e55751c367..53ed30b362 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/CodeEditor.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/CodeEditor.java @@ -19,11 +19,10 @@ */ package org.apache.dolphinscheduler.e2e.pages.common; -import org.openqa.selenium.By; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; -import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBys; import org.openqa.selenium.support.PageFactory; @@ -51,7 +50,7 @@ public final class CodeEditor { } public CodeEditor content(String content) { - new WebDriverWait(this.driver, Duration.ofSeconds(20)).until(ExpectedConditions.elementToBeClickable(editor)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(editor)); editor.click(); diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/HttpInput.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/HttpInput.java index ce3f07c819..770de59009 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/HttpInput.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/HttpInput.java @@ -22,6 +22,7 @@ package org.apache.dolphinscheduler.e2e.pages.common; import lombok.Getter; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; @@ -50,7 +51,7 @@ public class HttpInput { } public HttpInput content(String content) { - new WebDriverWait(this.driver, Duration.ofSeconds(20)).until(ExpectedConditions.elementToBeClickable(urlInput)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(urlInput)); urlInput().sendKeys(content); return this; } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/NavBarPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/NavBarPage.java index 0a6373977a..a6a64ccf92 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/NavBarPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/NavBarPage.java @@ -20,6 +20,7 @@ package org.apache.dolphinscheduler.e2e.pages.common; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.datasource.DataSourcePage; import org.apache.dolphinscheduler.e2e.pages.project.ProjectPage; import org.apache.dolphinscheduler.e2e.pages.resource.ResourcePage; @@ -64,26 +65,30 @@ public class NavBarPage { public T goToNav(Class nav) { if (nav == ProjectPage.class) { - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.elementToBeClickable(projectTab)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(projectTab)); projectTab.click(); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/projects/list")); return nav.cast(new ProjectPage(driver)); } if (nav == SecurityPage.class) { - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.elementToBeClickable(securityTab)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(securityTab)); securityTab.click(); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/security/tenant-manage")); return nav.cast(new SecurityPage(driver)); } if (nav == ResourcePage.class) { - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.elementToBeClickable(resourceTab)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(resourceTab)); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", resourceTab()); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/resource/file-manage")); return nav.cast(new ResourcePage(driver)); } if (nav == DataSourcePage.class) { - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.elementToBeClickable(dataSourceTab)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(dataSourceTab)); dataSourceTab.click(); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/datasource")); return nav.cast(new DataSourcePage(driver)); } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/datasource/DataSourcePage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/datasource/DataSourcePage.java index bd2f7e795b..7f84ac29de 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/datasource/DataSourcePage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/datasource/DataSourcePage.java @@ -22,6 +22,7 @@ package org.apache.dolphinscheduler.e2e.pages.datasource; import lombok.Getter; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import java.security.Key; @@ -74,12 +75,12 @@ public class DataSourcePage extends NavBarPage implements NavBarPage.NavBarItem String jdbcParams) { buttonCreateDataSource().click(); - new WebDriverWait(driver, Duration.ofSeconds(10)).until(ExpectedConditions.visibilityOfElementLocated( + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.visibilityOfElementLocated( new By.ByClassName("dialog-source-modal"))); dataSourceModal().findElement(By.className(dataSourceType.toUpperCase()+"-box")).click(); - new WebDriverWait(driver, Duration.ofSeconds(10)).until(ExpectedConditions.textToBePresentInElement(driver.findElement(By.className("dialog-create-data-source")), dataSourceType.toUpperCase())); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.textToBePresentInElement(driver.findElement(By.className("dialog-create-data-source")), dataSourceType.toUpperCase())); createDataSourceForm().inputDataSourceName().sendKeys(dataSourceName); createDataSourceForm().inputDataSourceDescription().sendKeys(dataSourceDescription); diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectDetailPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectDetailPage.java index 2ad24507ab..6e06db5039 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectDetailPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectDetailPage.java @@ -19,16 +19,22 @@ */ package org.apache.dolphinscheduler.e2e.pages.project; +import java.time.Duration; +import lombok.SneakyThrows; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import org.apache.dolphinscheduler.e2e.pages.project.workflow.TaskInstanceTab; import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowDefinitionTab; import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowInstanceTab; +import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.support.FindBy; import lombok.Getter; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; @Getter public final class ProjectDetailPage extends NavBarPage { @@ -45,17 +51,21 @@ public final class ProjectDetailPage extends NavBarPage { super(driver); } + @SneakyThrows public T goToTab(Class tab) { if (tab == WorkflowDefinitionTab.class) { menuProcessDefinition().click(); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/workflow-definition")); return tab.cast(new WorkflowDefinitionTab(driver)); } if (tab == WorkflowInstanceTab.class) { menuProcessInstances().click(); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/workflow/instances")); return tab.cast(new WorkflowInstanceTab(driver)); } if (tab == TaskInstanceTab.class) { menuTaskInstances().click(); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/task/instances")); return tab.cast(new TaskInstanceTab(driver)); } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectPage.java index 6219fab099..8be97f5db9 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectPage.java @@ -35,6 +35,8 @@ import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import lombok.Getter; +import static org.assertj.core.api.Assertions.assertThat; +import static org.testcontainers.shaded.org.awaitility.Awaitility.await; @Getter public final class ProjectPage extends NavBarPage implements NavBarItem { @@ -64,17 +66,25 @@ public final class ProjectPage extends NavBarPage implements NavBarItem { buttonCreateProject().click(); createProjectForm().inputProjectName().sendKeys(project); createProjectForm().buttonSubmit().click(); + return this; + } + public ProjectPage createProjectUntilSuccess(String project) { + create(project); + await().untilAsserted(() -> assertThat(projectList()) + .as("project list should contain newly-created project") + .anyMatch(it -> it.getText().contains(project))); return this; } + public ProjectPage delete(String project) { projectList() - .stream() - .filter(it -> it.getText().contains(project)) - .findFirst() - .orElseThrow(() -> new RuntimeException("Cannot find project: " + project)) - .findElement(By.className("delete")).click(); + .stream() + .filter(it -> it.getText().contains(project)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Cannot find project: " + project)) + .findElement(By.className("delete")).click(); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", buttonConfirm()); @@ -83,11 +93,11 @@ public final class ProjectPage extends NavBarPage implements NavBarItem { public ProjectDetailPage goTo(String project) { projectList().stream() - .filter(it -> it.getText().contains(project)) - .map(it -> it.findElement(By.className("project-name")).findElement(new By.ByTagName("button"))) - .findFirst() - .orElseThrow(() -> new RuntimeException("Cannot click the project item")) - .click(); + .filter(it -> it.getText().contains(project)) + .map(it -> it.findElement(By.className("project-name")).findElement(new By.ByTagName("button"))) + .findFirst() + .orElseThrow(() -> new RuntimeException("Cannot click the project item")) + .click(); return new ProjectDetailPage(driver); } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/TaskInstanceTab.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/TaskInstanceTab.java index 06f76676b8..d1d81b70e4 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/TaskInstanceTab.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/TaskInstanceTab.java @@ -35,7 +35,8 @@ import java.util.stream.Collectors; @Getter public final class TaskInstanceTab extends NavBarPage implements ProjectDetailPage.Tab { - @FindBy(className = "items-task-instances") + + @FindBy(className = "batch-task-instance-items") private List instanceList; public TaskInstanceTab(RemoteWebDriver driver) { @@ -47,7 +48,6 @@ public final class TaskInstanceTab extends NavBarPage implements ProjectDetailPa .stream() .filter(WebElement::isDisplayed) .map(Row::new) - .filter(row -> !row.name().isEmpty()) .collect(Collectors.toList()); } @@ -55,12 +55,25 @@ public final class TaskInstanceTab extends NavBarPage implements ProjectDetailPa public static class Row { private final WebElement row; - public String state() { - return row.findElement(By.className("task-instance-state")).getText(); + public String taskInstanceName() { + return row.findElement(By.cssSelector("td[data-col-key=name]")).getText(); + } + + public String workflowInstanceName() { + return row.findElement(By.cssSelector("td[data-col-key=processInstanceName]")).getText(); + } + + public int retryTimes() { + return Integer.parseInt(row.findElement(By.cssSelector("td[data-col-key=retryTimes]")).getText()); + } + + public boolean isSuccess() { + return !row.findElements(By.className("success")).isEmpty(); } - public String name() { - return row.findElement(By.className("task-instance-name")).getText(); + public boolean isFailed() { + return !row.findElements(By.className("failed")).isEmpty(); } + } } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowForm.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowForm.java index 58c5c96051..69573ab7ff 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowForm.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowForm.java @@ -19,6 +19,7 @@ */ package org.apache.dolphinscheduler.e2e.pages.project.workflow; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.project.workflow.task.HttpTaskForm; import org.apache.dolphinscheduler.e2e.pages.project.workflow.task.ShellTaskForm; import org.apache.dolphinscheduler.e2e.pages.project.workflow.task.SubWorkflowTaskForm; @@ -93,7 +94,7 @@ public final class WorkflowForm { } public WebElement getTask(String taskName) { - List tasks = new WebDriverWait(driver, Duration.ofSeconds(20)) + List tasks = WebDriverWaitFactory.createWebDriverWait(driver) .until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector("svg > g > g[class^='x6-graph-svg-stage'] > g[data-shape^='dag-task']"))); WebElement task = tasks.stream() diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowInstanceTab.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowInstanceTab.java index f55c5d0263..2b7fa28274 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowInstanceTab.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowInstanceTab.java @@ -86,6 +86,10 @@ public final class WorkflowInstanceTab extends NavBarPage implements ProjectDeta public static class Row { private final WebElement row; + public String workflowInstanceName() { + return row.findElement(By.className("workflow-name")).getText(); + } + public WebElement rerunButton() { return row.findElement(By.className("btn-rerun")); } @@ -94,6 +98,10 @@ public final class WorkflowInstanceTab extends NavBarPage implements ProjectDeta return !row.findElements(By.className("success")).isEmpty(); } + public boolean isFailed() { + return !row.findElements(By.className("failed")).isEmpty(); + } + public int executionTime() { return Integer.parseInt(row.findElement(By.className("workflow-run-times")).getText()); } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowRunDialog.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowRunDialog.java index 9a3e24fb8a..9e337be43e 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowRunDialog.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowRunDialog.java @@ -19,6 +19,7 @@ */ package org.apache.dolphinscheduler.e2e.pages.project.workflow; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; @@ -44,7 +45,7 @@ public final class WorkflowRunDialog { } public WorkflowDefinitionTab submit() { - new WebDriverWait(parent().driver(), Duration.ofSeconds(20)).until(ExpectedConditions.elementToBeClickable(buttonSubmit())); + WebDriverWaitFactory.createWebDriverWait(parent.driver()).until(ExpectedConditions.elementToBeClickable(buttonSubmit())); buttonSubmit().click(); diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SubWorkflowTaskForm.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SubWorkflowTaskForm.java index d89037feaa..6f328ddf23 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SubWorkflowTaskForm.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SubWorkflowTaskForm.java @@ -19,6 +19,7 @@ */ package org.apache.dolphinscheduler.e2e.pages.project.workflow.task; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowForm; import lombok.Getter; @@ -54,11 +55,11 @@ public final class SubWorkflowTaskForm extends TaskNodeForm { } public SubWorkflowTaskForm childNode(String node) { - new WebDriverWait(driver, Duration.ofSeconds(5)).until(ExpectedConditions.elementToBeClickable(btnSelectChildNodeDropdown)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(btnSelectChildNodeDropdown)); btnSelectChildNodeDropdown().click(); - new WebDriverWait(driver, Duration.ofSeconds(5)).until(ExpectedConditions.visibilityOfElementLocated(By.className( + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.visibilityOfElementLocated(By.className( "n-base-select-option__content"))); selectChildNode() diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SwitchTaskForm.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SwitchTaskForm.java index 988a00c7bd..480f5b410b 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SwitchTaskForm.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SwitchTaskForm.java @@ -20,6 +20,7 @@ package org.apache.dolphinscheduler.e2e.pages.project.workflow.task; import lombok.Getter; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowForm; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; @@ -54,7 +55,7 @@ public final class SwitchTaskForm extends TaskNodeForm { final By optionsLocator = By.className("option-else-branches"); - new WebDriverWait(parent().driver(), Duration.ofSeconds(10)) + WebDriverWaitFactory.createWebDriverWait(parent().driver()) .until(ExpectedConditions.visibilityOfElementLocated(optionsLocator)); List webElements = parent().driver().findElements(optionsLocator); @@ -79,7 +80,7 @@ public final class SwitchTaskForm extends TaskNodeForm { final By optionsLocator = By.className("option-if-branches"); - new WebDriverWait(parent().driver(), Duration.ofSeconds(10)) + WebDriverWaitFactory.createWebDriverWait(parent().driver()) .until(ExpectedConditions.visibilityOfElementLocated(optionsLocator)); List webElements = parent().driver().findElements(optionsLocator); diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/TaskNodeForm.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/TaskNodeForm.java index fadfd6c38b..5d0a944b02 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/TaskNodeForm.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/TaskNodeForm.java @@ -20,6 +20,7 @@ package org.apache.dolphinscheduler.e2e.pages.project.workflow.task; import lombok.Getter; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowForm; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; @@ -28,13 +29,11 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBys; import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.ByChained; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import java.time.Duration; import java.util.List; -import java.util.stream.Stream; @Getter public abstract class TaskNodeForm { @@ -48,14 +47,14 @@ public abstract class TaskNodeForm { private WebElement buttonSubmit; @FindBys({ - @FindBy(className = "input-param-key"), - @FindBy(tagName = "input"), + @FindBy(className = "input-param-key"), + @FindBy(tagName = "input"), }) private List inputParamKey; @FindBys({ - @FindBy(className = "input-param-value"), - @FindBy(tagName = "input"), + @FindBy(className = "input-param-value"), + @FindBy(tagName = "input"), }) private List inputParamValue; @@ -80,6 +79,13 @@ public abstract class TaskNodeForm { @FindBy(className = "btn-create-custom-parameter") private WebElement buttonCreateCustomParameters; + @FindBys({ + @FindBy(className = "resource-select"), + @FindBy(className = "n-base-selection"), + }) + private WebElement selectResource; + + private final WorkflowForm parent; TaskNodeForm(WorkflowForm parent) { @@ -118,15 +124,15 @@ public abstract class TaskNodeForm { return this; } - public TaskNodeForm selectEnv(String envName){ - ((JavascriptExecutor)parent().driver()).executeScript("arguments[0].click();", selectEnv); + public TaskNodeForm selectEnv(String envName) { + ((JavascriptExecutor) parent().driver()).executeScript("arguments[0].click();", selectEnv); final By optionsLocator = By.className("n-base-selection-input__content"); - new WebDriverWait(parent.driver(), Duration.ofSeconds(20)) + WebDriverWaitFactory.createWebDriverWait(parent().driver()) .until(ExpectedConditions.visibilityOfElementLocated(optionsLocator)); - List webElements = parent.driver().findElements(optionsLocator); + List webElements = parent.driver().findElements(optionsLocator); webElements.stream() .filter(it -> it.getText().contains(envName)) @@ -138,14 +144,14 @@ public abstract class TaskNodeForm { } public TaskNodeForm preTask(String preTaskName) { - ((JavascriptExecutor)parent().driver()).executeScript("arguments[0].click();", selectPreTasks); + ((JavascriptExecutor) parent().driver()).executeScript("arguments[0].click();", selectPreTasks); final By optionsLocator = By.className("option-pre-tasks"); - new WebDriverWait(parent.driver(), Duration.ofSeconds(20)) + WebDriverWaitFactory.createWebDriverWait(parent.driver()) .until(ExpectedConditions.visibilityOfElementLocated(optionsLocator)); - List webElements = parent.driver().findElements(optionsLocator); + List webElements = parent.driver().findElements(optionsLocator); webElements.stream() .filter(it -> it.getText().contains(preTaskName)) .findFirst() @@ -157,6 +163,23 @@ public abstract class TaskNodeForm { return this; } + public TaskNodeForm selectResource(String resourceName) { + ((JavascriptExecutor) parent().driver()).executeScript("arguments[0].click();", selectResource); + + final By optionsLocator = By.className("n-tree-node-content__text"); + + WebDriverWaitFactory.createWebDriverWait(parent().driver()).until(ExpectedConditions.visibilityOfElementLocated(optionsLocator)); + + parent().driver() + .findElements(optionsLocator) + .stream() + .filter(it -> it.getText().startsWith(resourceName)) + .findFirst() + .orElseThrow(() -> new RuntimeException("No such resource: " + resourceName)) + .click(); + return this; + } + public WorkflowForm submit() { buttonSubmit.click(); diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FileManagePage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FileManagePage.java index a2a780be9d..412acf0f2a 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FileManagePage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FileManagePage.java @@ -22,6 +22,7 @@ package org.apache.dolphinscheduler.e2e.pages.resource; import lombok.Getter; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.common.CodeEditor; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; @@ -42,6 +43,8 @@ import org.openqa.selenium.support.ui.WebDriverWait; import java.io.File; import java.time.Duration; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; +import static org.testcontainers.shaded.org.awaitility.Awaitility.await; @Getter @@ -92,6 +95,7 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab { uploadFileBox = new UploadFileBox(); editFileBox = new EditFileBox(); + } public FileManagePage createDirectory(String name) { @@ -114,13 +118,13 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab { public FileManagePage rename(String currentName, String AfterName) { fileList() - .stream() - .filter(it -> it.getText().contains(currentName)) - .flatMap(it -> it.findElements(By.className("btn-rename")).stream()) - .filter(WebElement::isDisplayed) - .findFirst() - .orElseThrow(() -> new RuntimeException("No rename button in file manage list")) - .click(); + .stream() + .filter(it -> it.getText().contains(currentName)) + .flatMap(it -> it.findElements(By.className("btn-rename")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No rename button in file manage list")) + .click(); renameBox().inputName().sendKeys(Keys.CONTROL + "a"); renameBox().inputName().sendKeys(Keys.BACK_SPACE); @@ -132,12 +136,12 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab { public FileManagePage createSubDirectory(String directoryName, String subDirectoryName) { fileList() - .stream() - .filter(it -> it.getText().contains(directoryName)) - .filter(WebElement::isDisplayed) - .findFirst() - .orElseThrow(() -> new RuntimeException(String.format("No %s in file manage list", directoryName))) - .click(); + .stream() + .filter(it -> it.getText().contains(directoryName)) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException(String.format("No %s in file manage list", directoryName))) + .click(); buttonCreateDirectory().click(); @@ -149,42 +153,61 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab { public FileManagePage delete(String name) { fileList() - .stream() - .filter(it -> it.getText().contains(name)) - .flatMap(it -> it.findElements(By.className("btn-delete")).stream()) - .filter(WebElement::isDisplayed) - .findFirst() - .orElseThrow(() -> new RuntimeException("No delete button in file manage list")) - .click(); + .stream() + .filter(it -> it.getText().contains(name)) + .flatMap(it -> it.findElements(By.className("btn-delete")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No delete button in file manage list")) + .click(); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", buttonConfirm()); return this; } + // todo: add file type public FileManagePage createFile(String fileName, String scripts) { + + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(buttonCreateFile())); + buttonCreateFile().click(); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/resource/file/create")); + createFileBox().inputFileName().sendKeys(fileName); createFileBox().codeEditor().content(scripts); createFileBox().buttonSubmit().click(); + // todo: check if the operation is successful + return this; + } + + public FileManagePage createFileUntilSuccess(String fileName, String scripts) { + + createFile(fileName, scripts); + await() + .untilAsserted(() -> + assertThat(fileList()) + .as("File list should contain newly-created file: " + fileName) + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(fileName))); return this; } public FileManagePage editFile(String fileName, String scripts) { fileList() - .stream() - .filter(it -> it.getText().contains(fileName)) - .flatMap(it -> it.findElements(By.className("btn-edit")).stream()) - .filter(WebElement::isDisplayed) - .findFirst() - .orElseThrow(() -> new RuntimeException("No edit button in file manage list")) - .click(); + .stream() + .filter(it -> it.getText().contains(fileName)) + .flatMap(it -> it.findElements(By.className("btn-edit")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No edit button in file manage list")) + .click(); - new WebDriverWait(driver, Duration.ofSeconds(20)).until(ExpectedConditions.urlContains("/edit")); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/edit")); - new WebDriverWait(driver, Duration.ofSeconds(20)).until(ExpectedConditions.textToBePresentInElement(driver.findElement(By.tagName("body")), fileName)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.textToBePresentInElement(driver.findElement(By.tagName("body")), fileName)); editFileBox().codeEditor().content(scripts); editFileBox().buttonSubmit().click(); @@ -205,13 +228,13 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab { public FileManagePage downloadFile(String fileName) { fileList() - .stream() - .filter(it -> it.getText().contains(fileName)) - .flatMap(it -> it.findElements(By.className("btn-download")).stream()) - .filter(WebElement::isDisplayed) - .findFirst() - .orElseThrow(() -> new RuntimeException("No download button in file manage list")) - .click(); + .stream() + .filter(it -> it.getText().contains(fileName)) + .flatMap(it -> it.findElements(By.className("btn-download")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No download button in file manage list")) + .click(); return this; } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java index 933a6df85e..23264147f8 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java @@ -19,6 +19,7 @@ */ package org.apache.dolphinscheduler.e2e.pages.resource; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import java.time.Duration; @@ -27,6 +28,7 @@ import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.PageFactory; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; @@ -40,14 +42,16 @@ public class ResourcePage extends NavBarPage implements NavBarPage.NavBarItem { public ResourcePage(RemoteWebDriver driver) { super(driver); + + PageFactory.initElements(driver, this); } public T goToTab(Class tab) { if (tab == FileManagePage.class) { - new WebDriverWait(driver, Duration.ofSeconds(20)).until(ExpectedConditions.urlContains("/resource")); - new WebDriverWait(driver, Duration.ofSeconds(20)).until(ExpectedConditions.elementToBeClickable(fileManageTab)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/resource")); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(fileManageTab)); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", fileManageTab()); - new WebDriverWait(driver, Duration.ofSeconds(20)).until(ExpectedConditions.urlContains("/file-manage")); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/file-manage")); return tab.cast(new FileManagePage(driver)); } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/EnvironmentPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/EnvironmentPage.java index 5d9f9bea36..c318c257e3 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/EnvironmentPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/EnvironmentPage.java @@ -19,6 +19,7 @@ package org.apache.dolphinscheduler.e2e.pages.security; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import java.time.Duration; @@ -67,7 +68,7 @@ public final class EnvironmentPage extends NavBarPage implements SecurityPage.Ta createEnvironmentForm().inputEnvironmentDesc().sendKeys(desc); editEnvironmentForm().btnSelectWorkerGroupDropdown().click(); - new WebDriverWait(driver, Duration.ofSeconds(20)).until(ExpectedConditions.visibilityOfElementLocated(new By.ByClassName( + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.visibilityOfElementLocated(new By.ByClassName( "n-base-select-option__content"))); editEnvironmentForm().selectWorkerGroupList() .stream() @@ -106,7 +107,7 @@ public final class EnvironmentPage extends NavBarPage implements SecurityPage.Ta if (editEnvironmentForm().selectedWorkerGroup().getAttribute("innerHTML").equals(workerGroup)) { editEnvironmentForm().btnSelectWorkerGroupDropdown().click(); - new WebDriverWait(driver, Duration.ofSeconds(20)).until(ExpectedConditions.visibilityOfElementLocated(new By.ByClassName( + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.visibilityOfElementLocated(new By.ByClassName( "n-base-select-option__content"))); editEnvironmentForm().selectWorkerGroupList() .stream() diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java index 5a5bb9c277..11cb748f7b 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java @@ -20,6 +20,7 @@ package org.apache.dolphinscheduler.e2e.pages.security; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage.NavBarItem; @@ -67,59 +68,60 @@ public class SecurityPage extends NavBarPage implements NavBarItem { } public T goToTab(Class tab) { + if (tab == TenantPage.class) { - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.urlContains("/security")); - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.elementToBeClickable(menuTenantManage)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(menuTenantManage)); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", menuTenantManage()); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/security/tenant-manage")); return tab.cast(new TenantPage(driver)); } if (tab == UserPage.class) { - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.urlContains("/security")); - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.elementToBeClickable(menUserManage)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(menUserManage)); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", menUserManage()); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/security/user-manage")); return tab.cast(new UserPage(driver)); } if (tab == WorkerGroupPage.class) { - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.urlContains("/security")); - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.elementToBeClickable(menWorkerGroupManage)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(menWorkerGroupManage)); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", menWorkerGroupManage()); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/security/worker-group-manage")); return tab.cast(new WorkerGroupPage(driver)); } if (tab == QueuePage.class) { - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.urlContains("/security")); - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.elementToBeClickable(menuQueueManage)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(menuQueueManage)); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", menuQueueManage()); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/security/yarn-queue-manage")); return tab.cast(new QueuePage(driver)); } if (tab == EnvironmentPage.class) { - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.urlContains("/security")); - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.elementToBeClickable(menuEnvironmentManage)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(menuEnvironmentManage)); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", menuEnvironmentManage()); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/security/environment-manage")); return tab.cast(new EnvironmentPage(driver)); } if (tab == ClusterPage.class) { - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.urlContains("/security")); - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.elementToBeClickable(menuClusterManage)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(menuClusterManage)); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", menuClusterManage()); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/security/cluster-manage")); return tab.cast(new ClusterPage(driver)); } if (tab == TokenPage.class) { - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.urlContains("/security")); - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.elementToBeClickable(menuTokenManage)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(menuTokenManage)); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", menuTokenManage()); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/security/token-manage")); return tab.cast(new TokenPage(driver)); } if (tab == NamespacePage.class) { - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.urlContains("/security")); - new WebDriverWait(driver, Duration.ofSeconds(60)).until(ExpectedConditions.elementToBeClickable(menuNamespaceManage)); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(menuNamespaceManage)); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", menuNamespaceManage()); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.urlContains("/security/k8s-namespace-manage")); return tab.cast(new NamespacePage(driver)); } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TenantPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TenantPage.java index cb24af307f..e6b9f877c1 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TenantPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TenantPage.java @@ -19,10 +19,14 @@ package org.apache.dolphinscheduler.e2e.pages.security; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.apache.dolphinscheduler.e2e.models.tenant.ITenant; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import java.util.List; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowInstanceTab; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.Keys; @@ -33,6 +37,9 @@ import org.openqa.selenium.support.FindBys; import org.openqa.selenium.support.PageFactory; import lombok.Getter; +import org.openqa.selenium.support.pagefactory.ByChained; +import static org.assertj.core.api.Assertions.assertThat; +import static org.testcontainers.shaded.org.awaitility.Awaitility.await; @Getter public final class TenantPage extends NavBarPage implements SecurityPage.Tab { @@ -43,8 +50,8 @@ public final class TenantPage extends NavBarPage implements SecurityPage.Tab { private List tenantList; @FindBys({ - @FindBy(className = "n-popconfirm__action"), - @FindBy(className = "n-button--primary-type"), + @FindBy(className = "n-popconfirm__action"), + @FindBy(className = "n-button--primary-type"), }) private WebElement buttonConfirm; @@ -61,11 +68,28 @@ public final class TenantPage extends NavBarPage implements SecurityPage.Tab { editTenantForm = new TenantForm(); } + public List tenants() { + return tenantList.stream() + .filter(WebElement::isDisplayed) + .map(Row::new) + .collect(Collectors.toList()); + } + + public boolean containsTenant(String tenant) { + return tenantList.stream() + .anyMatch(it -> it.findElement(By.className("tenant-code")).getText().contains(tenant)); + } + + public TenantPage create(ITenant tenant) { + return create(tenant.getTenantCode(), tenant.getDescription()); + } + public TenantPage create(String tenant) { return create(tenant, ""); } public TenantPage create(String tenant, String description) { + buttonCreateTenant().click(); tenantForm().inputTenantCode().sendKeys(tenant); tenantForm().inputDescription().sendKeys(description); @@ -76,12 +100,12 @@ public final class TenantPage extends NavBarPage implements SecurityPage.Tab { public TenantPage update(String tenant, String description) { tenantList().stream() - .filter(it -> it.findElement(By.className("tenant-code")).getAttribute("innerHTML").contains(tenant)) - .flatMap(it -> it.findElements(By.className("edit")).stream()) - .filter(WebElement::isDisplayed) - .findFirst() - .orElseThrow(() -> new RuntimeException("No edit button in tenant list")) - .click(); + .filter(it -> it.findElement(By.className("tenant-code")).getAttribute("innerHTML").contains(tenant)) + .flatMap(it -> it.findElements(By.className("edit")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No edit button in tenant list")) + .click(); editTenantForm().inputDescription().sendKeys(Keys.CONTROL + "a"); editTenantForm().inputDescription().sendKeys(Keys.BACK_SPACE); @@ -93,13 +117,13 @@ public final class TenantPage extends NavBarPage implements SecurityPage.Tab { public TenantPage delete(String tenant) { tenantList() - .stream() - .filter(it -> it.getText().contains(tenant)) - .flatMap(it -> it.findElements(By.className("delete")).stream()) - .filter(WebElement::isDisplayed) - .findFirst() - .orElseThrow(() -> new RuntimeException("No delete button in user list")) - .click(); + .stream() + .filter(it -> it.getText().contains(tenant)) + .flatMap(it -> it.findElements(By.className("delete")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No delete button in user list")) + .click(); ((JavascriptExecutor) driver).executeScript("arguments[0].click();", buttonConfirm()); @@ -133,4 +157,14 @@ public final class TenantPage extends NavBarPage implements SecurityPage.Tab { @FindBy(className = "btn-cancel") private WebElement buttonCancel; } + + @RequiredArgsConstructor + public static class Row { + private final WebElement row; + + public String tenantCode() { + return row.findElement(By.cssSelector("td[data-col-key=tenantCode]")).getText(); + } + + } } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TokenPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TokenPage.java index 5def2ad64f..7be82a840a 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TokenPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TokenPage.java @@ -19,6 +19,7 @@ package org.apache.dolphinscheduler.e2e.pages.security; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage.Tab; @@ -69,9 +70,9 @@ public final class TokenPage extends NavBarPage implements Tab { public TokenPage create(String userName) { buttonCreateToken().click(); - new WebDriverWait(driver, Duration.ofSeconds(30)).until(ExpectedConditions.elementToBeClickable(createTokenForm().selectUserNameDropdown())); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(createTokenForm().selectUserNameDropdown())); createTokenForm().selectUserNameDropdown().click(); - new WebDriverWait(driver, Duration.ofSeconds(30)).until(ExpectedConditions.visibilityOfElementLocated(new By.ByClassName( + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.visibilityOfElementLocated(new By.ByClassName( "n-base-select-option__content"))); createTokenForm().selectUserNameList() .stream() @@ -81,7 +82,7 @@ public final class TokenPage extends NavBarPage implements Tab { userName))) .click(); - new WebDriverWait(driver, Duration.ofSeconds(30)).until(ExpectedConditions.elementToBeClickable(createTokenForm().buttonGenerateToken())); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(createTokenForm().buttonGenerateToken())); createTokenForm().buttonGenerateToken().click(); createTokenForm().buttonSubmit().click(); @@ -98,9 +99,9 @@ public final class TokenPage extends NavBarPage implements Tab { .orElseThrow(() -> new RuntimeException("No edit button in token list")) .click(); - new WebDriverWait(driver, Duration.ofSeconds(30)).until(ExpectedConditions.elementToBeClickable(editTokenForm().buttonGenerateToken())); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(editTokenForm().buttonGenerateToken())); editTokenForm().buttonGenerateToken().click(); - new WebDriverWait(driver, Duration.ofSeconds(30)).until(ExpectedConditions.elementToBeClickable(editTokenForm().buttonGenerateToken())); + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.elementToBeClickable(editTokenForm().buttonGenerateToken())); editTokenForm().buttonSubmit().click(); diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/UserPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/UserPage.java index 26a236ad52..1ee52e8a28 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/UserPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/UserPage.java @@ -19,6 +19,8 @@ package org.apache.dolphinscheduler.e2e.pages.security; +import org.apache.dolphinscheduler.e2e.core.WebDriverWaitFactory; +import org.apache.dolphinscheduler.e2e.models.users.IUser; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import java.time.Duration; @@ -67,7 +69,7 @@ public final class UserPage extends NavBarPage implements SecurityPage.Tab { createUserForm().btnSelectTenantDropdown().click(); - new WebDriverWait(driver, Duration.ofSeconds(30)).until(ExpectedConditions.visibilityOfElementLocated(new By.ByClassName( + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.visibilityOfElementLocated(new By.ByClassName( "n-base-select-option__content"))); createUserForm().selectTenant() @@ -84,7 +86,19 @@ public final class UserPage extends NavBarPage implements SecurityPage.Tab { return this; } - public UserPage update(String user, String editUser, String editEmail, String editPhone, + public UserPage update(IUser user) { + return update( + user.getUserName(), + user.getUserName(), + user.getEmail(), + user.getPhone(), + user.getTenant()); + } + + public UserPage update(String user, + String editUser, + String editEmail, + String editPhone, String tenant) { userList().stream() .filter(it -> it.findElement(By.className("name")).getAttribute("innerHTML").contains(user)) @@ -100,7 +114,7 @@ public final class UserPage extends NavBarPage implements SecurityPage.Tab { createUserForm().btnSelectTenantDropdown().click(); - new WebDriverWait(driver, Duration.ofSeconds(30)).until(ExpectedConditions.visibilityOfElementLocated(new By.ByClassName( + WebDriverWaitFactory.createWebDriverWait(driver).until(ExpectedConditions.visibilityOfElementLocated(new By.ByClassName( "n-base-select-option__content"))); createUserForm().selectTenant() diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java index dcf22a2d6d..d40afe1f3a 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java @@ -80,7 +80,7 @@ final class DolphinSchedulerExtension implements BeforeAllCallback, AfterAllCall @SuppressWarnings("UnstableApiUsage") public void beforeAll(ExtensionContext context) throws IOException { Awaitility.setDefaultTimeout(Duration.ofSeconds(60)); - Awaitility.setDefaultPollInterval(Duration.ofSeconds(2)); + Awaitility.setDefaultPollInterval(Duration.ofMillis(500)); setRecordPath(); @@ -115,6 +115,7 @@ final class DolphinSchedulerExtension implements BeforeAllCallback, AfterAllCall .filter(it -> Modifier.isStatic(it.getModifiers())) .filter(f -> WebDriver.class.isAssignableFrom(f.getType())) .forEach(it -> setDriver(clazz, it)); + WebDriverHolder.setWebDriver(driver); } private void runInLocal() { diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/WebDriverHolder.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/WebDriverHolder.java new file mode 100644 index 0000000000..48e8c53e92 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/WebDriverHolder.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.e2e.core; + +import org.openqa.selenium.remote.RemoteWebDriver; + +public class WebDriverHolder { + + public static RemoteWebDriver browser; + + public static void setWebDriver(RemoteWebDriver driver) { + browser = driver; + } + + public static RemoteWebDriver getWebDriver() { + return browser; + } + +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/WebDriverWaitFactory.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/WebDriverWaitFactory.java new file mode 100644 index 0000000000..946fe071ab --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/WebDriverWaitFactory.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.e2e.core; + +import java.time.Duration; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.ui.WebDriverWait; + +public class WebDriverWaitFactory { + + private static final Duration DEFAULT_INTERVAL = Duration.ofMillis(500); + + private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(60); + + /** + * Create a WebDriverWait instance with default timeout 60s and interval 100ms. + */ + public static WebDriverWait createWebDriverWait(WebDriver driver) { + return createWebDriverWait(driver, DEFAULT_TIMEOUT); + } + + public static WebDriverWait createWebDriverWait(WebDriver driver, Duration timeout) { + return new WebDriverWait(driver, timeout, DEFAULT_INTERVAL); + } + + public static WebDriverWait createWebDriverWait(WebDriver driver, Duration timeout, Duration interval) { + return new WebDriverWait(driver, timeout, interval); + } + +} diff --git a/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/ResourceType.java b/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/ResourceType.java index 09132ebac9..8be58ebb15 100644 --- a/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/ResourceType.java +++ b/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/ResourceType.java @@ -28,7 +28,7 @@ import com.baomidou.mybatisplus.annotation.EnumValue; public enum ResourceType { /** - * 0 file, 1 udf + * 0 file */ FILE(0, "file"), ALL(2, "all"); diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-resources.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-resources.ts index 90ba0a40a7..f9fa187314 100644 --- a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-resources.ts +++ b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-resources.ts @@ -123,6 +123,7 @@ export function useResources( return { type: 'tree-select', field: 'resourceList', + class: 'resource-select', name: t('project.node.resources'), span: span, options: resourcesOptions, diff --git a/dolphinscheduler-ui/src/views/projects/task/instance/batch-task.tsx b/dolphinscheduler-ui/src/views/projects/task/instance/batch-task.tsx index 03ca177df2..9e2eed243b 100644 --- a/dolphinscheduler-ui/src/views/projects/task/instance/batch-task.tsx +++ b/dolphinscheduler-ui/src/views/projects/task/instance/batch-task.tsx @@ -283,6 +283,7 @@ const BatchTaskInstance = defineComponent({