mirror of
https://gitee.com/dolphinscheduler/DolphinScheduler.git
synced 2024-11-29 18:58:05 +08:00
Add end-to-end test framework and some basic cases (#6419)
This commit is contained in:
parent
fa102afad0
commit
251255009a
70
.github/workflows/e2e.yml
vendored
70
.github/workflows/e2e.yml
vendored
@ -15,60 +15,54 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
on: ["pull_request"]
|
||||
env:
|
||||
DOCKER_DIR: ./docker
|
||||
LOG_DIR: /tmp/dolphinscheduler
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- e2e
|
||||
|
||||
name: Test
|
||||
env:
|
||||
TAG: ci
|
||||
RECORDING_PATH: /tmp/recording
|
||||
|
||||
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
|
||||
|
@ -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/
|
||||
|
98
dolphinscheduler-e2e/README.md
Normal file
98
dolphinscheduler-e2e/README.md
Normal file
@ -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.
|
40
dolphinscheduler-e2e/dolphinscheduler-e2e-case/pom.xml
Normal file
40
dolphinscheduler-e2e/dolphinscheduler-e2e-case/pom.xml
Normal file
@ -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>
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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:
|
32
dolphinscheduler-e2e/dolphinscheduler-e2e-core/pom.xml
Normal file
32
dolphinscheduler-e2e/dolphinscheduler-e2e-core/pom.xml
Normal file
@ -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>
|
@ -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();
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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>
|
20
dolphinscheduler-e2e/lombok.config
Normal file
20
dolphinscheduler-e2e/lombok.config
Normal file
@ -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
|
138
dolphinscheduler-e2e/pom.xml
Normal file
138
dolphinscheduler-e2e/pom.xml
Normal file
@ -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>
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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: {
|
||||
|
Loading…
Reference in New Issue
Block a user