Browse Source

[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>
dev
Wenjun Ruan 4 months ago committed by GitHub
parent
commit
46eff34e69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 12
      .github/workflows/api-test.yml
  2. 12
      .github/workflows/backend.yml
  3. 10
      .github/workflows/docs.yml
  4. 4
      .github/workflows/e2e-k8s.yml
  5. 20
      .github/workflows/e2e.yml
  6. 6
      .github/workflows/frontend.yml
  7. 2
      .github/workflows/issue-robot.yml
  8. 4
      .github/workflows/owasp-dependency-check.yaml
  9. 2
      .github/workflows/publish-docker.yaml
  10. 2
      .github/workflows/publish-helm-chart.yaml
  11. 4
      .github/workflows/unit-test.yml
  12. 10
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ResourcesController.java
  13. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/ClickhouseDataSourceE2ETest.java
  14. 5
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java
  15. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/HiveDataSourceE2ETest.java
  16. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/MysqlDataSourceE2ETest.java
  17. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/PostgresDataSourceE2ETest.java
  18. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/SqlServerDataSourceE2ETest.java
  19. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UserE2ETest.java
  20. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkerGroupE2ETest.java
  21. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java
  22. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowHttpTaskE2ETest.java
  23. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowJavaTaskE2ETest.java
  24. 4
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowSwitchE2ETest.java
  25. 260
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/tasks/ShellTaskE2ETest.java
  26. 219
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/workflow/BaseWorkflowE2ETest.java
  27. 31
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/BootstrapTenant.java
  28. 30
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/DefaultTenant.java
  29. 26
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/tenant/ITenant.java
  30. 62
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/users/AdminUser.java
  31. 35
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/models/users/IUser.java
  32. 13
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java
  33. 5
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/CodeEditor.java
  34. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/HttpInput.java
  35. 13
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/NavBarPage.java
  36. 5
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/datasource/DataSourcePage.java
  37. 10
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectDetailPage.java
  38. 30
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectPage.java
  39. 25
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/TaskInstanceTab.java
  40. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowForm.java
  41. 8
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowInstanceTab.java
  42. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowRunDialog.java
  43. 5
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SubWorkflowTaskForm.java
  44. 5
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SwitchTaskForm.java
  45. 49
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/TaskNodeForm.java
  46. 95
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FileManagePage.java
  47. 10
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java
  48. 5
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/EnvironmentPage.java
  49. 34
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java
  50. 64
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TenantPage.java
  51. 11
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TokenPage.java
  52. 20
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/UserPage.java
  53. 3
      dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java
  54. 34
      dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/WebDriverHolder.java
  55. 45
      dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/WebDriverWaitFactory.java
  56. 2
      dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/ResourceType.java
  57. 1
      dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-resources.ts
  58. 1
      dolphinscheduler-ui/src/views/projects/task/instance/batch-task.tsx

12
.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:

12
.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

10
.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

4
.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

20
.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:

6
.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

2
.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

4
.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:

2
.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:

2
.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

4
.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

10
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<List<ResourceComponent>> 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)),

3
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())

5
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())

3
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())

3
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())

3
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())

3
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())

3
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();

3
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);

3
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)

3
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)

3
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)

4
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();
});
}
}

260
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()
.<ShellTaskForm>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()
.<ShellTaskForm>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()
.<ShellTaskForm>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()
.<ShellTaskForm>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()
.<ShellTaskForm>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()
.<ShellTaskForm>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);
}
}

219
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<WorkflowInstanceTab.Row> 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<TaskInstanceTab.Row> 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<TaskInstanceTab.Row> 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);
}
}

31
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";
}
}

30
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 "";
}
}

26
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();
}

62
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();
}
}

35
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();
}

13
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);
}

5
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();

3
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;
}

13
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 extends NavBarItem> T goToNav(Class<T> 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));
}

5
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);

10
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 extends Tab> T goToTab(Class<T> 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));
}

30
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);
}

25
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<WebElement> 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();
}
}
}

3
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<WebElement> tasks = new WebDriverWait(driver, Duration.ofSeconds(20))
List<WebElement> 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()

8
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());
}

3
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();

5
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()

5
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<WebElement> 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<WebElement> webElements = parent().driver().findElements(optionsLocator);

49
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<WebElement> inputParamKey;
@FindBys({
@FindBy(className = "input-param-value"),
@FindBy(tagName = "input"),
@FindBy(className = "input-param-value"),
@FindBy(tagName = "input"),
})
private List<WebElement> 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<WebElement> webElements = parent.driver().findElements(optionsLocator);
List<WebElement> 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<WebElement> webElements = parent.driver().findElements(optionsLocator);
List<WebElement> 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();

95
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;
}

10
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 extends ResourcePage.Tab> T goToTab(Class<T> 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));
}

5
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()

34
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 extends SecurityPage.Tab> T goToTab(Class<T> 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));
}

64
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<WebElement> 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<Row> 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();
}
}
}

11
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();

20
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()

3
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() {

34
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;
}
}

45
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);
}
}

2
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");

1
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,

1
dolphinscheduler-ui/src/views/projects/task/instance/batch-task.tsx

@ -283,6 +283,7 @@ const BatchTaskInstance = defineComponent({
<Card title={t('project.task.batch_task')}>
<NSpace vertical>
<NDataTable
row-class-name='batch-task-instance-items'
loading={loadingRef}
columns={this.columns}
data={this.tableData}

Loading…
Cancel
Save