You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by le...@apache.org on 2021/10/20 13:14:34 UTC
[dolphinscheduler] branch dev updated: Add end-to-end test
framework and some basic cases (#6419)
This is an automated email from the ASF dual-hosted git repository.
leonbao pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git
The following commit(s) were added to refs/heads/dev by this push:
new 2512550 Add end-to-end test framework and some basic cases (#6419)
2512550 is described below
commit 251255009a857656abf0fe7776b5ae4d68eb4cf7
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Wed Oct 20 21:14:26 2021 +0800
Add end-to-end test framework and some basic cases (#6419)
---
.github/workflows/e2e.yml | 68 ++++----
docker/build/hooks/build | 42 +----
dolphinscheduler-e2e/README.md | 98 +++++++++++
.../dolphinscheduler-e2e-case/pom.xml | 40 +++++
.../e2e/cases/security/TenantE2ETest.java | 98 +++++++++++
.../dolphinscheduler/e2e/pages/LoginPage.java | 47 ++++++
.../dolphinscheduler/e2e/pages/TenantPage.java | 78 +++++++++
.../resources/docker/tenant/docker-compose.yaml | 35 ++++
.../dolphinscheduler-e2e-core/pom.xml | 32 ++++
.../e2e/core/DolphinScheduler.java | 41 +++++
.../e2e/core/DolphinSchedulerExtension.java | 187 +++++++++++++++++++++
.../dolphinscheduler/e2e/core/TestDescription.java | 55 ++++++
.../src/main/resources/log4j2.xml | 31 ++++
dolphinscheduler-e2e/lombok.config | 20 +++
dolphinscheduler-e2e/pom.xml | 138 +++++++++++++++
.../dolphinscheduler/server/StandaloneServer.java | 2 +
.../pages/tenement/_source/createTenement.vue | 5 +
.../pages/security/pages/tenement/_source/list.vue | 4 +-
.../home/pages/security/pages/tenement/index.vue | 2 +-
dolphinscheduler-ui/src/js/conf/login/App.vue | 4 +-
.../src/js/module/components/popup/popover.vue | 12 +-
21 files changed, 963 insertions(+), 76 deletions(-)
diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index 2fbbffa..e707259 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -15,60 +15,54 @@
# limitations under the License.
#
-on: ["pull_request"]
+on:
+ pull_request:
+ push:
+ branches:
+ - e2e
+
env:
- DOCKER_DIR: ./docker
- LOG_DIR: /tmp/dolphinscheduler
+ TAG: ci
+ RECORDING_PATH: /tmp/recording
-name: Test
+name: E2E
concurrency:
group: e2e-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
- test:
- name: E2E
+ e2e:
+ name: ${{ matrix.case.name }}
runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ case:
+ - name: Tenant
+ class: org.apache.dolphinscheduler.e2e.cases.security.TenantE2ETest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Sanity Check
uses: ./.github/actions/sanity-check
- - uses: actions/cache@v1
+ - name: Cache local Maven repository
+ uses: actions/cache@v2
with:
path: ~/.m2/repository
- key: ${{ runner.os }}-maven
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: ${{ runner.os }}-maven-
- name: Build Image
+ run: TAG=ci sh ./docker/build/hooks/build
+ - name: Run Test
run: |
- sh ./docker/build/hooks/build
- - name: Docker Run
- run: |
- export VERSION=$(cat $(pwd)/pom.xml | grep '<revision>' -m 1 | awk '{print $1}' | sed 's/<revision>//' | sed 's/<\/revision>//')
- sed -i "s/apache\/dolphinscheduler:latest/apache\/dolphinscheduler:${VERSION}/g" $(pwd)/docker/docker-swarm/docker-compose.yml
- docker-compose -f $(pwd)/docker/docker-swarm/docker-compose.yml up -d
- - name: Check Server Status
- run: sh $(pwd)/docker/docker-swarm/check
- - name: Prepare e2e env
- run: |
- sudo apt-get install -y libxss1 libappindicator1 libindicator7 xvfb unzip libgbm1
- wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- sudo dpkg -i google-chrome*.deb
- sudo apt-get install -f -y
- google-chrome -version
- googleVersion=$(curl -s https://chromedriver.storage.googleapis.com/LATEST_RELEASE)
- wget -N https://chromedriver.storage.googleapis.com/${googleVersion}/chromedriver_linux64.zip
- unzip chromedriver_linux64.zip
- sudo mv -f chromedriver /usr/local/share/chromedriver
- sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver
-# - name: Run e2e Test
-# run: cd ./e2e && mvn -B clean test
- - name: Collect logs
- if: failure()
- uses: actions/upload-artifact@v2
+ ./mvnw -f dolphinscheduler-e2e/pom.xml -am \
+ -DfailIfNoTests=false \
+ -Dtest=${{ matrix.case.class }} test
+ - uses: actions/upload-artifact@v2
+ if: always()
+ name: Upload Recording
with:
- name: dslogs
- path: ${{ github.workspace }}/docker/docker-swarm/dolphinscheduler-logs
-
-
+ name: recording
+ path: ${{ env.RECORDING_PATH }}
+ retention-days: 1
diff --git a/docker/build/hooks/build b/docker/build/hooks/build
index 70ea260..1e6a965 100755
--- a/docker/build/hooks/build
+++ b/docker/build/hooks/build
@@ -18,41 +18,17 @@
set -e
-echo "------ dolphinscheduler start - build -------"
-printenv
+ROOT_DIR=$(dirname "$0")/../../..
+MVN="$ROOT_DIR"/mvnw
+VERSION=$("$MVN" -q -DforceStdout -N org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version)
-if [ -z "${VERSION}" ]
-then
- echo "set default environment variable [VERSION]"
- export VERSION=$(cat $(pwd)/pom.xml | grep '<version>' -m 1 | awk '{print $1}' | sed 's/<version>//' | sed 's/<\/version>//')
-fi
+DOCKER_REPO=${DOCKER_REPO:-"apache/dolphinscheduler"}
+TAG=${TAG:-"$VERSION"}
-if [ "${DOCKER_REPO}x" = "x" ]
-then
- echo "set default environment variable [DOCKER_REPO]"
- export DOCKER_REPO='apache/dolphinscheduler'
-fi
+echo "Building Docker image as: $DOCKER_REPO:$TAG"
-echo "Version: $VERSION"
-echo "Repo: $DOCKER_REPO"
+"$MVN" -B clean package -Prelease -Dmaven.test.skip=true -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120
-echo -e "Current Directory is $(pwd)\n"
+cp "$ROOT_DIR"/dolphinscheduler-dist/target/apache-dolphinscheduler-$VERSION-bin.tar.gz "$ROOT_DIR"/docker/build/
-# maven package(Project Directory)
-echo -e "./mvnw -B clean package -Prelease -Dmaven.test.skip=true -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120"
-./mvnw -B clean package -Prelease -Dmaven.test.skip=true -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120
-
-# mv dolphinscheduler-bin.tar.gz file to docker/build directory
-echo -e "mv $(pwd)/dolphinscheduler-dist/target/apache-dolphinscheduler-${VERSION}-bin.tar.gz $(pwd)/docker/build/\n"
-mv $(pwd)/dolphinscheduler-dist/target/apache-dolphinscheduler-${VERSION}-bin.tar.gz $(pwd)/docker/build/
-
-# docker build
-BUILD_COMMAND="docker build --build-arg VERSION=${VERSION} -t $DOCKER_REPO:${VERSION} $(pwd)/docker/build/"
-echo -e "$BUILD_COMMAND\n"
-if (docker info 2> /dev/null | grep -i "ERROR"); then
- sudo $BUILD_COMMAND
-else
- $BUILD_COMMAND
-fi
-
-echo "------ dolphinscheduler end - build -------"
+docker build --build-arg VERSION=$VERSION -t $DOCKER_REPO:$TAG "$ROOT_DIR"/docker/build/
diff --git a/dolphinscheduler-e2e/README.md b/dolphinscheduler-e2e/README.md
new file mode 100644
index 0000000..35c3043
--- /dev/null
+++ b/dolphinscheduler-e2e/README.md
@@ -0,0 +1,98 @@
+# DolphinScheduler End-to-End Test
+
+## Page Object Model
+
+DolphinScheduler End-to-End test respects
+the [Page Object Model (POM)](https://www.selenium.dev/documentation/guidelines/page_object_models/) design pattern.
+Every page of DolphinScheduler is abstracted into a class for better maintainability.
+
+### Example
+
+The login page is abstracted
+as [`LoginPage`](dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java), with the
+following fields,
+
+```java
+public final class LoginPage {
+ @FindBy(id = "input-username")
+ private WebElement inputUsername;
+
+ @FindBy(id = "input-password")
+ private WebElement inputPassword;
+
+ @FindBy(id = "button-login")
+ private WebElement buttonLogin;
+}
+```
+
+where `inputUsername`, `inputPassword` and `buttonLogin` are the main elements on UI that we are interested in. They are
+annotated with `FindBy` so that the test framework knows how to locate the elements on UI. You can locate the elements
+by `id`, `className`, `css` selector, `tagName`, or even `xpath`, please refer
+to [the JavaDoc](https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/support/FindBy.html).
+
+**Note:** for better maintainability, it's essential to add some convenient `id` or `class` on UI for the wanted
+elements if needed, avoid using too complex `xpath` selector or `css` selector that is not maintainable when UI have
+styles changes.
+
+With those fields declared, we should also initialize them with a web driver. Here we pass the web driver into the
+constructor and invoke `PageFactory.initElements` to initialize those fields,
+
+```java
+public final class LoginPage {
+ // ...
+ public LoginPage(RemoteWebDriver driver) {
+ this.driver = driver;
+
+ PageFactory.initElements(driver, this);
+ }
+}
+```
+
+then, all those UI elements are properly filled in.
+
+## Test Environment Setup
+
+DolphinScheduler End-to-End test uses [testcontainers](https://www.testcontainers.org) to set up the testing
+environment, with docker compose.
+
+Typically, every test case needs one or more `docker-compose.yaml` files to set up all needed components, and expose the
+DolphinScheduler UI port for testing. You can use `@DolphinScheduler(composeFiles = "")` and pass
+the `docker-compose.yaml` files to automatically set up the environment in the test class.
+
+```java
+
+@DolphinScheduler(composeFiles = "docker/tenant/docker-compose.yaml")
+class TenantE2ETest {
+}
+```
+
+You can get the web driver that is ready for testing in the class by adding a field of type `RemoteWebDriver`, which
+will be automatically injected via the testing framework.
+
+```java
+
+@DolphinScheduler(composeFiles = "docker/tenant/docker-compose.yaml")
+class TenantE2ETest {
+ private RemoteWebDriver browser;
+}
+```
+
+Then the field `browser` can be used in the test methods.
+
+```java
+
+@DolphinScheduler(composeFiles = "docker/tenant/docker-compose.yaml")
+class TenantE2ETest {
+ private RemoteWebDriver browser;
+
+ @Test
+ void testLogin() {
+ final LoginPage page = new LoginPage(browser); // <<-- use the browser injected
+ }
+}
+```
+
+## Notes
+
+- For UI tests, it's common that the pages might need some time to load, or the operations might need some time to
+ complete, we can use `await().untilAsserted(() -> {})` to wait for the assertions.
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/pom.xml b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/pom.xml
new file mode 100644
index 0000000..17e63be
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to 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. Apache Software Foundation (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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>dolphinscheduler-e2e</artifactId>
+ <groupId>org.apache.dolphinscheduler</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dolphinscheduler-e2e-case</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.dolphinscheduler</groupId>
+ <artifactId>dolphinscheduler-e2e-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/security/TenantE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/security/TenantE2ETest.java
new file mode 100644
index 0000000..ab3159a
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/security/TenantE2ETest.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to 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. Apache Software Foundation (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.security;
+
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+
+import org.apache.dolphinscheduler.e2e.core.DolphinScheduler;
+import org.apache.dolphinscheduler.e2e.pages.LoginPage;
+import org.apache.dolphinscheduler.e2e.pages.TenantPage;
+
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.remote.RemoteWebDriver;
+
+@DolphinScheduler(composeFiles = "docker/tenant/docker-compose.yaml")
+class TenantE2ETest {
+ private RemoteWebDriver browser;
+
+ @Test
+ @Order(1)
+ void testLogin() {
+ final LoginPage page = new LoginPage(browser);
+ page.inputUsername().sendKeys("admin");
+ page.inputPassword().sendKeys("dolphinscheduler123");
+ page.buttonLogin().click();
+ }
+
+ @Test
+ @Order(10)
+ void testCreateTenant() {
+ final TenantPage page = new TenantPage(browser);
+ final String tenant = System.getProperty("user.name");
+
+ page.buttonCreateTenant().click();
+ page.createTenantForm().inputTenantCode().sendKeys(tenant);
+ page.createTenantForm().inputDescription().sendKeys("Test");
+ page.createTenantForm().buttonSubmit().click();
+
+ await().untilAsserted(() -> assertThat(page.tenantList())
+ .as("Tenant list should contain newly-created tenant")
+ .extracting(WebElement::getText)
+ .anyMatch(it -> it.contains(tenant)));
+ }
+
+ @Test
+ @Order(20)
+ void testCreateDuplicateTenant() {
+ final String tenant = System.getProperty("user.name");
+ final TenantPage page = new TenantPage(browser);
+ page.buttonCreateTenant().click();
+ page.createTenantForm().inputTenantCode().sendKeys(tenant);
+ page.createTenantForm().inputDescription().sendKeys("Test");
+ page.createTenantForm().buttonSubmit().click();
+
+ await().untilAsserted(() -> assertThat(browser.findElementByTagName("body")
+ .getText().contains("already exists"))
+ .as("Should fail when creating a duplicate tenant")
+ .isTrue());
+
+ page.createTenantForm().buttonCancel().click();
+ }
+
+ @Test
+ @Order(30)
+ void testDeleteTenant() {
+ final String tenant = System.getProperty("user.name");
+ final TenantPage page = new TenantPage(browser);
+
+ page.tenantList()
+ .stream()
+ .filter(it -> it.getText().contains(tenant))
+ .findFirst()
+ .ifPresent(it -> it.findElement(By.className("delete")).click());
+
+ page.buttonConfirm().click();
+ }
+}
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java
new file mode 100644
index 0000000..a772517
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to 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. Apache Software Foundation (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.pages;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.remote.RemoteWebDriver;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.PageFactory;
+
+import lombok.Getter;
+
+@Getter
+public final class LoginPage {
+ private final RemoteWebDriver driver;
+
+ @FindBy(id = "input-username")
+ private WebElement inputUsername;
+
+ @FindBy(id = "input-password")
+ private WebElement inputPassword;
+
+ @FindBy(id = "button-login")
+ private WebElement buttonLogin;
+
+ public LoginPage(RemoteWebDriver driver) {
+ this.driver = driver;
+
+ PageFactory.initElements(driver, this);
+ }
+}
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/TenantPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/TenantPage.java
new file mode 100644
index 0000000..da97349
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/TenantPage.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to 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. Apache Software Foundation (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.pages;
+
+import java.util.List;
+
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.FindBys;
+import org.openqa.selenium.support.PageFactory;
+
+import lombok.Getter;
+
+@Getter
+public final class TenantPage {
+ private final WebDriver driver;
+
+ @FindBy(id = "button-create-tenant")
+ private WebElement buttonCreateTenant;
+
+ @FindBy(className = "rows-tenant")
+ private List<WebElement> tenantList;
+
+ @FindBys({
+ @FindBy(className = "el-popconfirm"),
+ @FindBy(className = "el-button--primary"),
+ })
+ private WebElement buttonConfirm;
+
+ private final CreateTenantForm createTenantForm;
+
+ public TenantPage(WebDriver driver) {
+ this.driver = driver;
+ this.createTenantForm = new CreateTenantForm();
+
+ PageFactory.initElements(driver, this);
+ }
+
+ @Getter
+ public class CreateTenantForm {
+ CreateTenantForm() {
+ PageFactory.initElements(driver, this);
+ }
+
+ @FindBy(id = "input-tenant-code")
+ private WebElement inputTenantCode;
+
+ @FindBy(id = "select-queue")
+ private WebElement selectQueue;
+
+ @FindBy(id = "input-description")
+ private WebElement inputDescription;
+
+ @FindBy(id = "button-submit")
+ private WebElement buttonSubmit;
+
+ @FindBy(id = "button-cancel")
+ private WebElement buttonCancel;
+ }
+}
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/tenant/docker-compose.yaml b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/tenant/docker-compose.yaml
new file mode 100644
index 0000000..13075d3
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/tenant/docker-compose.yaml
@@ -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.
+#
+
+version: "2.1"
+
+services:
+ dolphinscheduler:
+ image: apache/dolphinscheduler:ci
+ command: [ standalone-server ]
+ expose:
+ - 12345
+ networks:
+ - e2e
+ healthcheck:
+ test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/12345" ]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+
+networks:
+ e2e:
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/pom.xml b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/pom.xml
new file mode 100644
index 0000000..060810c
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/pom.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to 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. Apache Software Foundation (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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>dolphinscheduler-e2e</artifactId>
+ <groupId>org.apache.dolphinscheduler</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dolphinscheduler-e2e-core</artifactId>
+</project>
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinScheduler.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinScheduler.java
new file mode 100644
index 0000000..8d49ca3
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinScheduler.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to 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. Apache Software Foundation (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.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+@Inherited
+@Testcontainers
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@TestMethodOrder(OrderAnnotation.class)
+@ExtendWith(DolphinSchedulerExtension.class)
+public @interface DolphinScheduler {
+ String[] composeFiles();
+}
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java
new file mode 100644
index 0000000..d7f3232
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to 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. Apache Software Foundation (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 static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_ALL;
+import static org.testcontainers.containers.VncRecordingContainer.VncRecordingFormat.MP4;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.chrome.ChromeOptions;
+import org.openqa.selenium.remote.RemoteWebDriver;
+import org.testcontainers.containers.BrowserWebDriverContainer;
+import org.testcontainers.containers.ContainerState;
+import org.testcontainers.containers.DockerComposeContainer;
+import org.testcontainers.containers.Network;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.shaded.org.apache.commons.lang.SystemUtils;
+import org.testcontainers.shaded.org.awaitility.Awaitility;
+
+import com.google.common.base.Strings;
+import com.google.common.net.HostAndPort;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+final class DolphinSchedulerExtension
+ implements BeforeAllCallback, AfterAllCallback,
+ BeforeEachCallback {
+ private final boolean LOCAL_MODE = Objects.equals(System.getProperty("local"), "true");
+
+ private RemoteWebDriver driver;
+ private DockerComposeContainer<?> compose;
+ private BrowserWebDriverContainer<?> browser;
+
+ @Override
+ @SuppressWarnings("UnstableApiUsage")
+ public void beforeAll(ExtensionContext context) throws IOException {
+ Awaitility.setDefaultTimeout(Duration.ofSeconds(5));
+ Awaitility.setDefaultPollInterval(Duration.ofSeconds(1));
+
+ Network network = null;
+ HostAndPort address = null;
+ String rootPath = "/";
+ if (!LOCAL_MODE) {
+ compose = createDockerCompose(context);
+ compose.start();
+
+ final ContainerState dsContainer = compose.getContainerByServiceName("dolphinscheduler_1")
+ .orElseThrow(() -> new RuntimeException("Failed to find a container named 'dolphinscheduler'"));
+ final String networkId = dsContainer.getContainerInfo().getNetworkSettings().getNetworks().keySet().iterator().next();
+ network = new Network() {
+ @Override
+ public String getId() {
+ return networkId;
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return null;
+ }
+ };
+ address = HostAndPort.fromParts("dolphinscheduler", 12345);
+ rootPath = "/dolphinscheduler";
+ }
+
+ final Path record;
+ if (!Strings.isNullOrEmpty(System.getenv("RECORDING_PATH"))) {
+ record = Paths.get(System.getenv("RECORDING_PATH"));
+ if (!record.toFile().exists()) {
+ if (!record.toFile().mkdir()) {
+ throw new IOException("Failed to create recording directory: " + record.toAbsolutePath());
+ }
+ }
+ } else {
+ record = Files.createTempDirectory("record-");
+ }
+ browser = new BrowserWebDriverContainer<>()
+ .withCapabilities(new ChromeOptions())
+ .withRecordingMode(RECORD_ALL, record.toFile(), MP4);
+ if (network != null) {
+ browser.withNetwork(network);
+ }
+ browser.start();
+
+ driver = browser.getWebDriver();
+
+ driver.manage().timeouts()
+ .implicitlyWait(5, TimeUnit.SECONDS)
+ .pageLoadTimeout(5, TimeUnit.SECONDS);
+ if (address == null) {
+ try {
+ address = HostAndPort.fromParts(browser.getTestHostIpAddress(), 8888);
+ } catch (UnsupportedOperationException ignored) {
+ if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_MAC_OSX) {
+ address = HostAndPort.fromParts("host.docker.internal", 8888);
+ }
+ }
+ }
+ if (address == null) {
+ throw new UnsupportedOperationException("Unsupported operation system");
+ }
+ driver.get(new URL("http", address.getHost(), address.getPort(), rootPath).toString());
+
+ browser.beforeTest(new TestDescription(context));
+ }
+
+ @Override
+ public void afterAll(ExtensionContext context) {
+ browser.afterTest(new TestDescription(context), Optional.empty());
+ browser.stop();
+ if (compose != null) {
+ compose.stop();
+ }
+ }
+
+ @Override
+ public void beforeEach(ExtensionContext context) {
+ final Object instance = context.getRequiredTestInstance();
+ Stream.of(instance.getClass().getDeclaredFields())
+ .filter(f -> WebDriver.class.isAssignableFrom(f.getType()))
+ .forEach(it -> {
+ try {
+ it.setAccessible(true);
+ it.set(instance, driver);
+ } catch (IllegalAccessException e) {
+ LOGGER.error("Failed to inject web driver to field: {}", it.getName(), e);
+ }
+ });
+ }
+
+ private DockerComposeContainer<?> createDockerCompose(ExtensionContext context) {
+ final Class<?> clazz = context.getRequiredTestClass();
+ final DolphinScheduler annotation = clazz.getAnnotation(DolphinScheduler.class);
+ final List<File> files = Stream.of(annotation.composeFiles())
+ .map(it -> DolphinScheduler.class.getClassLoader().getResource(it))
+ .filter(Objects::nonNull)
+ .map(URL::getPath)
+ .map(File::new)
+ .collect(Collectors.toList());
+ compose = new DockerComposeContainer<>(files)
+ .withPull(true)
+ .withTailChildContainers(true)
+ .waitingFor("dolphinscheduler_1", Wait.forHealthcheck());
+
+ return compose;
+ }
+}
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/TestDescription.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/TestDescription.java
new file mode 100644
index 0000000..16f366c
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/TestDescription.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to 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. Apache Software Foundation (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 static java.nio.charset.StandardCharsets.UTF_8;
+
+import static org.junit.platform.commons.util.StringUtils.isBlank;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import org.junit.jupiter.api.extension.ExtensionContext;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+final class TestDescription implements org.testcontainers.lifecycle.TestDescription {
+ private static final String UNKNOWN_NAME = "unknown";
+
+ private final ExtensionContext context;
+
+ @Override
+ public String getTestId() {
+ return context.getUniqueId();
+ }
+
+ @Override
+ public String getFilesystemFriendlyName() {
+ final String contextId = context.getUniqueId();
+ try {
+ return (isBlank(contextId))
+ ? UNKNOWN_NAME
+ : URLEncoder.encode(contextId, UTF_8.toString());
+ } catch (UnsupportedEncodingException e) {
+ return UNKNOWN_NAME;
+ }
+ }
+}
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/resources/log4j2.xml b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..167e6e6
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/resources/log4j2.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ ~
+ -->
+
+<Configuration status="DEBUG">
+ <Appenders>
+ <Console name="Console" target="SYSTEM_OUT">
+ <PatternLayout charset="UTF-8" pattern="%d %c %L [%t] %-5p %x - %m%n"/>
+ </Console>
+ </Appenders>
+ <Loggers>
+ <Root level="INFO">
+ <AppenderRef ref="Console"/>
+ </Root>
+ </Loggers>
+</Configuration>
diff --git a/dolphinscheduler-e2e/lombok.config b/dolphinscheduler-e2e/lombok.config
new file mode 100644
index 0000000..0056b8f
--- /dev/null
+++ b/dolphinscheduler-e2e/lombok.config
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+lombok.accessors.fluent=true
+lombok.log.fieldname=LOGGER
+lombok.accessors.fluent=true
diff --git a/dolphinscheduler-e2e/pom.xml b/dolphinscheduler-e2e/pom.xml
new file mode 100644
index 0000000..cb841af
--- /dev/null
+++ b/dolphinscheduler-e2e/pom.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.dolphinscheduler</groupId>
+ <artifactId>dolphinscheduler-e2e</artifactId>
+ <packaging>pom</packaging>
+ <version>1.0-SNAPSHOT</version>
+
+ <modules>
+ <module>dolphinscheduler-e2e-core</module>
+ <module>dolphinscheduler-e2e-case</module>
+ </modules>
+
+ <properties>
+ <maven.compiler.source>8</maven.compiler.source>
+ <maven.compiler.target>8</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+
+ <junit.version>5.7.2</junit.version>
+ <selenium.version>3.141.59</selenium.version>
+ <lombok.version>1.18.20</lombok.version>
+ <assertj-core.version>3.20.2</assertj-core.version>
+ <awaitility.version>4.1.0</awaitility.version>
+ <kotlin.version>1.5.30</kotlin.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.30</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-slf4j-impl</artifactId>
+ <version>2.14.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>selenium</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.seleniumhq.selenium</groupId>
+ <artifactId>selenium-chrome-driver</artifactId>
+ <version>${selenium.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.seleniumhq.selenium</groupId>
+ <artifactId>selenium-support</artifactId>
+ <version>${selenium.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>${assertj-core.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.awaitility</groupId>
+ <artifactId>awaitility</artifactId>
+ <version>${awaitility.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <version>${lombok.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.junit</groupId>
+ <artifactId>junit-bom</artifactId>
+ <version>${junit.version}</version>
+ <scope>import</scope>
+ <type>pom</type>
+ </dependency>
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers-bom</artifactId>
+ <version>1.16.0</version>
+ <scope>import</scope>
+ <type>pom</type>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.22.2</version>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/dolphinscheduler-standalone-server/src/main/java/org/apache/dolphinscheduler/server/StandaloneServer.java b/dolphinscheduler-standalone-server/src/main/java/org/apache/dolphinscheduler/server/StandaloneServer.java
index bc42871..e5a9b00 100644
--- a/dolphinscheduler-standalone-server/src/main/java/org/apache/dolphinscheduler/server/StandaloneServer.java
+++ b/dolphinscheduler-standalone-server/src/main/java/org/apache/dolphinscheduler/server/StandaloneServer.java
@@ -125,6 +125,8 @@ public class StandaloneServer {
if (Files.exists(taskPluginPath)) {
System.setProperty("task.plugin.binding", taskPluginPath.toString());
System.setProperty("task.plugin.dir", "");
+ } else {
+ System.setProperty("task.plugin.binding", "lib/plugin/task/shell");
}
}
}
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/tenement/_source/createTenement.vue b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/tenement/_source/createTenement.vue
index 3bc83a0..1e9b125 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/tenement/_source/createTenement.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/tenement/_source/createTenement.vue
@@ -16,6 +16,8 @@
*/
<template>
<m-popover
+ okId="button-submit"
+ cancelId="button-cancel"
ref="popover"
:ok-text="item ? $t('Edit') : $t('Submit')"
@ok="_ok"
@@ -26,6 +28,7 @@
<template slot="name"><strong>*</strong>{{$t('OS Tenant Code')}}</template>
<template slot="content">
<el-input
+ id="input-tenant-code"
type="input"
:disabled="item ? true : false"
v-model="tenantCode"
@@ -40,6 +43,7 @@
<template slot="content">
<el-select v-model="queueId" size="small">
<el-option
+ id="select-queue"
v-for="city in queueList"
:key="city.id"
:value="city.id"
@@ -52,6 +56,7 @@
<template slot="name">{{$t('Description')}}</template>
<template slot="content">
<el-input
+ id="input-description"
type="textarea"
v-model="description"
size="small"
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/tenement/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/tenement/_source/list.vue
index 4579137..df980f8 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/tenement/_source/list.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/tenement/_source/list.vue
@@ -17,7 +17,7 @@
<template>
<div class="list-model">
<div class="table-box">
- <el-table :data="list" size="mini" style="width: 100%">
+ <el-table :data="list" size="mini" style="width: 100%" row-class-name="rows-tenant">
<el-table-column type="index" :label="$t('#')" width="50"></el-table-column>
<el-table-column prop="tenantCode" :label="$t('OS Tenant Code')" min-width="100"></el-table-column>
<el-table-column :label="$t('Description')" min-width="100">
@@ -51,7 +51,7 @@
:title="$t('Delete?')"
@onConfirm="_delete(scope.row,scope.row.id)"
>
- <el-button type="danger" size="mini" icon="el-icon-delete" circle slot="reference"></el-button>
+ <el-button type="danger" size="mini" icon="el-icon-delete" circle slot="reference" class="delete"></el-button>
</el-popconfirm>
</el-tooltip>
</template>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/tenement/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/tenement/index.vue
index 5c82073..d6c5226 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/tenement/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/tenement/index.vue
@@ -19,7 +19,7 @@
<template slot="conditions">
<m-conditions @on-conditions="_onConditions">
<template slot="button-group" v-if="isADMIN">
- <el-button size="mini" @click="_create('')">{{$t('Create Tenant')}}</el-button>
+ <el-button id="button-create-tenant" size="mini" @click="_create('')">{{$t('Create Tenant')}}</el-button>
<el-dialog
:title="item ? $t('Edit Tenant') : $t('Create Tenant')"
v-if="createTenementDialog"
diff --git a/dolphinscheduler-ui/src/js/conf/login/App.vue b/dolphinscheduler-ui/src/js/conf/login/App.vue
index 29a4cdb..c4beda9 100644
--- a/dolphinscheduler-ui/src/js/conf/login/App.vue
+++ b/dolphinscheduler-ui/src/js/conf/login/App.vue
@@ -24,6 +24,7 @@
<label>{{$t('User Name')}}</label>
<div>
<el-input
+ id="input-username"
type="text"
v-model.trim="userName"
:placeholder="$t('Please enter user name')"
@@ -39,6 +40,7 @@
<label>{{$t('Password')}}</label>
<div>
<el-input
+ id="input-password"
type="password"
v-model="userPassword"
:placeholder="$t('Please enter your password')"
@@ -51,7 +53,7 @@
</p>
</div>
<div class="list" style="margin-top: 10px;">
- <el-button style="width: 365px" type="primary" round :loading="spinnerLoading" long @click="_ok">{{spinnerLoading ? $t('Loading...') : ` ${$t('Login')} `}} </el-button>
+ <el-button id="button-login" style="width: 365px" type="primary" round :loading="spinnerLoading" long @click="_ok">{{spinnerLoading ? $t('Loading...') : ` ${$t('Login')} `}} </el-button>
</div>
</div>
</div>
diff --git a/dolphinscheduler-ui/src/js/module/components/popup/popover.vue b/dolphinscheduler-ui/src/js/module/components/popup/popover.vue
index ee7ecc8..9d3bb6a 100644
--- a/dolphinscheduler-ui/src/js/module/components/popup/popover.vue
+++ b/dolphinscheduler-ui/src/js/module/components/popup/popover.vue
@@ -20,8 +20,8 @@
<slot name="content"></slot>
</div>
<div class="bottom-p">
- <el-button type="text" size="mini" round @click="close()" :disabled="disabled"> {{$t('Cancel')}} </el-button>
- <el-button type="primary" size="mini" round :loading="spinnerLoading" @click="ok()" :disabled="disabled || apDisabled">{{spinnerLoading ? $t('Loading...') : okText}} </el-button>
+ <el-button :id="cancelId" type="text" size="mini" round @click="close()" :disabled="disabled"> {{$t('Cancel')}} </el-button>
+ <el-button :id="okId" type="primary" size="mini" round :loading="spinnerLoading" @click="ok()" :disabled="disabled || apDisabled">{{spinnerLoading ? $t('Loading...') : okText}} </el-button>
</div>
</div>
</template>
@@ -47,6 +47,14 @@
asynLoading: {
type: Boolean,
default: false
+ },
+ cancelId: {
+ type: String,
+ default: ''
+ },
+ okId: {
+ type: String,
+ default: ''
}
},
methods: {