[E2E] add function manage test case (#8250)
This commit is contained in:
parent
01936a660e
commit
4b58df9aa8
|
|
@ -87,6 +87,8 @@ jobs:
|
||||||
class: org.apache.dolphinscheduler.e2e.cases.FileManageE2ETest
|
class: org.apache.dolphinscheduler.e2e.cases.FileManageE2ETest
|
||||||
- name: UdfManage
|
- name: UdfManage
|
||||||
class: org.apache.dolphinscheduler.e2e.cases.UdfManageE2ETest
|
class: org.apache.dolphinscheduler.e2e.cases.UdfManageE2ETest
|
||||||
|
- name: FunctionManage
|
||||||
|
class: org.apache.dolphinscheduler.e2e.cases.FunctionManageE2ETest
|
||||||
- name: MysqlDataSource
|
- name: MysqlDataSource
|
||||||
class: org.apache.dolphinscheduler.e2e.cases.MysqlDataSourceE2ETest
|
class: org.apache.dolphinscheduler.e2e.cases.MysqlDataSourceE2ETest
|
||||||
- name: ClickhouseDataSource
|
- name: ClickhouseDataSource
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,187 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.e2e.cases;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.awaitility.Awaitility.await;
|
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.e2e.core.Constants;
|
||||||
|
import org.apache.dolphinscheduler.e2e.core.DolphinScheduler;
|
||||||
|
import org.apache.dolphinscheduler.e2e.pages.LoginPage;
|
||||||
|
import org.apache.dolphinscheduler.e2e.pages.resource.FunctionManagePage;
|
||||||
|
import org.apache.dolphinscheduler.e2e.pages.resource.ResourcePage;
|
||||||
|
import org.apache.dolphinscheduler.e2e.pages.resource.UdfManagePage;
|
||||||
|
import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage;
|
||||||
|
import org.apache.dolphinscheduler.e2e.pages.security.TenantPage;
|
||||||
|
import org.apache.dolphinscheduler.e2e.pages.security.UserPage;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
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;
|
||||||
|
import org.openqa.selenium.support.ui.ExpectedConditions;
|
||||||
|
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||||
|
|
||||||
|
@DolphinScheduler(composeFiles = "docker/file-manage/docker-compose.yaml")
|
||||||
|
public class FunctionManageE2ETest {
|
||||||
|
private static RemoteWebDriver browser;
|
||||||
|
|
||||||
|
private static final String tenant = System.getProperty("user.name");
|
||||||
|
|
||||||
|
private static final String user = "admin";
|
||||||
|
|
||||||
|
private static final String password = "dolphinscheduler123";
|
||||||
|
|
||||||
|
private static final String email = "admin@gmail.com";
|
||||||
|
|
||||||
|
private static final String phone = "15800000000";
|
||||||
|
|
||||||
|
private static final String testUdfFunctionName = "test_function";
|
||||||
|
|
||||||
|
private static final String testRenameUdfFunctionName = "test_rename_function";
|
||||||
|
|
||||||
|
private static final String testUploadUdfFileName = "hive-jdbc-3.1.2.jar";
|
||||||
|
|
||||||
|
private static final String testClassName = "org.dolphinscheduler.UdfTest";
|
||||||
|
|
||||||
|
private static final String testDescription = "test_description";
|
||||||
|
|
||||||
|
private static final Path testUploadUdfFilePath = Constants.HOST_TMP_PATH.resolve(testUploadUdfFileName);
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
@SneakyThrows
|
||||||
|
public static void setup() {
|
||||||
|
TenantPage tenantPage = new LoginPage(browser)
|
||||||
|
.login(user, password)
|
||||||
|
.create(tenant);
|
||||||
|
|
||||||
|
await().untilAsserted(() -> assertThat(tenantPage.tenantList())
|
||||||
|
.as("Tenant list should contain newly-created tenant")
|
||||||
|
.extracting(WebElement::getText)
|
||||||
|
.anyMatch(it -> it.contains(tenant)));
|
||||||
|
|
||||||
|
downloadFile("https://repo1.maven.org/maven2/org/apache/hive/hive-jdbc/3.1.2/hive-jdbc-3.1.2.jar", testUploadUdfFilePath.toFile().getAbsolutePath());
|
||||||
|
|
||||||
|
UdfManagePage udfManagePage = tenantPage.goToNav(SecurityPage.class)
|
||||||
|
.goToTab(UserPage.class)
|
||||||
|
.update(user, user, password, email, phone)
|
||||||
|
.goToNav(ResourcePage.class)
|
||||||
|
.goToTab(UdfManagePage.class)
|
||||||
|
.uploadFile(testUploadUdfFilePath.toFile().getAbsolutePath());
|
||||||
|
|
||||||
|
new WebDriverWait(browser, 10).until(ExpectedConditions.invisibilityOfElementLocated(By.id("fileUpdateDialog")));
|
||||||
|
|
||||||
|
udfManagePage.goToNav(ResourcePage.class)
|
||||||
|
.goToTab(FunctionManagePage.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
@SneakyThrows
|
||||||
|
public static void cleanup() {
|
||||||
|
Files.walk(Constants.HOST_CHROME_DOWNLOAD_PATH)
|
||||||
|
.sorted(Comparator.reverseOrder())
|
||||||
|
.map(Path::toFile)
|
||||||
|
.forEach(File::delete);
|
||||||
|
|
||||||
|
Files.deleteIfExists(testUploadUdfFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void downloadFile(String downloadUrl, String filePath) throws Exception {
|
||||||
|
int byteRead;
|
||||||
|
|
||||||
|
URL url = new URL(downloadUrl);
|
||||||
|
|
||||||
|
URLConnection conn = url.openConnection();
|
||||||
|
InputStream inStream = conn.getInputStream();
|
||||||
|
FileOutputStream fs = new FileOutputStream(filePath);
|
||||||
|
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
while ((byteRead = inStream.read(buffer)) != -1) {
|
||||||
|
fs.write(buffer, 0, byteRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
inStream.close();
|
||||||
|
fs.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(10)
|
||||||
|
void testCreateUdfFunction() {
|
||||||
|
FunctionManagePage page = new FunctionManagePage(browser);
|
||||||
|
|
||||||
|
new WebDriverWait(page.driver(), 10)
|
||||||
|
.until(ExpectedConditions.urlContains("/#/resource/func"));
|
||||||
|
|
||||||
|
page.createUdfFunction(testUdfFunctionName, testClassName, testUploadUdfFileName, testDescription);
|
||||||
|
|
||||||
|
await().untilAsserted(() -> assertThat(page.functionList())
|
||||||
|
.as("Function list should contain newly-created file")
|
||||||
|
.extracting(WebElement::getText)
|
||||||
|
.anyMatch(it -> it.contains(testUdfFunctionName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(20)
|
||||||
|
void testRenameUdfFunction() {
|
||||||
|
FunctionManagePage page = new FunctionManagePage(browser);
|
||||||
|
|
||||||
|
browser.navigate().refresh();
|
||||||
|
|
||||||
|
page.renameUdfFunction(testUdfFunctionName, testRenameUdfFunctionName);
|
||||||
|
|
||||||
|
await().pollDelay(Duration.ofSeconds(2)).untilAsserted(() -> assertThat(page.functionList())
|
||||||
|
.as("Function list should contain newly-created file")
|
||||||
|
.extracting(WebElement::getText)
|
||||||
|
.anyMatch(it -> it.contains(testRenameUdfFunctionName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(30)
|
||||||
|
void testDeleteUdfFunction() {
|
||||||
|
FunctionManagePage page = new FunctionManagePage(browser);
|
||||||
|
|
||||||
|
page.deleteUdfFunction(testRenameUdfFunctionName);
|
||||||
|
|
||||||
|
await().untilAsserted(() -> {
|
||||||
|
browser.navigate().refresh();
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
page.functionList()
|
||||||
|
).noneMatch(
|
||||||
|
it -> it.getText().contains(testRenameUdfFunctionName)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,11 +24,154 @@ import lombok.Getter;
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage;
|
import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.remote.RemoteWebDriver;
|
import org.openqa.selenium.remote.RemoteWebDriver;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
import org.openqa.selenium.support.FindBys;
|
||||||
|
import org.openqa.selenium.support.PageFactory;
|
||||||
|
import org.openqa.selenium.support.ui.ExpectedConditions;
|
||||||
|
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class FunctionManagePage extends NavBarPage implements ResourcePage.Tab {
|
public class FunctionManagePage extends NavBarPage implements ResourcePage.Tab {
|
||||||
|
@FindBy(id = "btnCreateUdfFunction")
|
||||||
|
private WebElement buttonCreateUdfFunction;
|
||||||
|
|
||||||
|
@FindBy(className = "udf-function-items")
|
||||||
|
private List<WebElement> functionList;
|
||||||
|
|
||||||
|
@FindBys({
|
||||||
|
@FindBy(className = "el-popconfirm"),
|
||||||
|
@FindBy(className = "el-button--primary"),
|
||||||
|
})
|
||||||
|
private List<WebElement> buttonConfirm;
|
||||||
|
|
||||||
|
private final CreateUdfFunctionBox createUdfFunctionBox;
|
||||||
|
|
||||||
|
private final RenameUdfFunctionBox renameUdfFunctionBox;
|
||||||
|
|
||||||
public FunctionManagePage(RemoteWebDriver driver) {
|
public FunctionManagePage(RemoteWebDriver driver) {
|
||||||
super(driver);
|
super(driver);
|
||||||
|
|
||||||
|
createUdfFunctionBox = new CreateUdfFunctionBox();
|
||||||
|
|
||||||
|
renameUdfFunctionBox = new RenameUdfFunctionBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FunctionManagePage createUdfFunction(String udfFunctionName, String className, String udfResourceName, String description) {
|
||||||
|
buttonCreateUdfFunction().click();
|
||||||
|
|
||||||
|
createUdfFunctionBox().inputFunctionName().sendKeys(udfFunctionName);
|
||||||
|
|
||||||
|
createUdfFunctionBox().inputClassName().sendKeys(className);
|
||||||
|
|
||||||
|
createUdfFunctionBox().inputDescription().sendKeys(description);
|
||||||
|
|
||||||
|
createUdfFunctionBox().buttonUdfResourceDropDown().click();
|
||||||
|
|
||||||
|
createUdfFunctionBox().selectUdfResource()
|
||||||
|
.stream()
|
||||||
|
.filter(it -> it.getText().contains(udfResourceName))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new RuntimeException(String.format("No %s in udf resource list", udfResourceName)))
|
||||||
|
.click();
|
||||||
|
|
||||||
|
createUdfFunctionBox().buttonSubmit().click();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FunctionManagePage renameUdfFunction(String currentName, String afterName) {
|
||||||
|
functionList()
|
||||||
|
.stream()
|
||||||
|
.filter(it -> it.getText().contains(currentName))
|
||||||
|
.flatMap(it -> it.findElements(By.id("btnRename")).stream())
|
||||||
|
.filter(WebElement::isDisplayed)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new RuntimeException("No rename button in function manage list"))
|
||||||
|
.click();
|
||||||
|
|
||||||
|
new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(By.id("createUdfDialog")));
|
||||||
|
|
||||||
|
renameUdfFunctionBox().inputFunctionName().clear();
|
||||||
|
|
||||||
|
renameUdfFunctionBox().inputFunctionName().sendKeys(afterName);
|
||||||
|
|
||||||
|
renameUdfFunctionBox.buttonSubmit().click();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FunctionManagePage deleteUdfFunction(String udfFunctionName) {
|
||||||
|
functionList()
|
||||||
|
.stream()
|
||||||
|
.filter(it -> it.getText().contains(udfFunctionName))
|
||||||
|
.flatMap(it -> it.findElements(By.id("btnDelete")).stream())
|
||||||
|
.filter(WebElement::isDisplayed)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new RuntimeException("No delete button in udf resource list"))
|
||||||
|
.click();
|
||||||
|
|
||||||
|
buttonConfirm()
|
||||||
|
.stream()
|
||||||
|
.filter(WebElement::isDisplayed)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new RuntimeException("No confirm button when deleting in udf resource page"))
|
||||||
|
.click();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class CreateUdfFunctionBox {
|
||||||
|
CreateUdfFunctionBox() {
|
||||||
|
PageFactory.initElements(driver, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FindBy(id = "inputFunctionName")
|
||||||
|
private WebElement inputFunctionName;
|
||||||
|
|
||||||
|
@FindBy(id = "inputClassName")
|
||||||
|
private WebElement inputClassName;
|
||||||
|
|
||||||
|
@FindBy(id = "btnUdfResourceDropDown")
|
||||||
|
private WebElement buttonUdfResourceDropDown;
|
||||||
|
|
||||||
|
@FindBy(className = "vue-treeselect__menu")
|
||||||
|
private List<WebElement> selectUdfResource;
|
||||||
|
|
||||||
|
@FindBy(id = "inputDescription")
|
||||||
|
private WebElement inputDescription;
|
||||||
|
|
||||||
|
@FindBy(id = "btnSubmit")
|
||||||
|
private WebElement buttonSubmit;
|
||||||
|
|
||||||
|
@FindBy(id = "btnCancel")
|
||||||
|
private WebElement buttonCancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class RenameUdfFunctionBox {
|
||||||
|
RenameUdfFunctionBox() {
|
||||||
|
PageFactory.initElements(driver, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FindBy(id = "inputFunctionName")
|
||||||
|
private WebElement inputFunctionName;
|
||||||
|
|
||||||
|
@FindBy(id = "inputClassName")
|
||||||
|
private WebElement inputClassName;
|
||||||
|
|
||||||
|
@FindBy(id = "inputDescription")
|
||||||
|
private WebElement inputDescription;
|
||||||
|
|
||||||
|
@FindBy(id = "btnSubmit")
|
||||||
|
private WebElement buttonSubmit;
|
||||||
|
|
||||||
|
@FindBy(id = "btnCancel")
|
||||||
|
private WebElement buttonCancel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
<template slot="name"><strong>*</strong>{{$t('UDF Resources')}}</template>
|
<template slot="name"><strong>*</strong>{{$t('UDF Resources')}}</template>
|
||||||
<template slot="content">
|
<template slot="content">
|
||||||
<treeselect id="btnUdfResourceDropDown" style="width:535px;float:left;" v-model="resourceId" maxHeight="200" :disable-branch-nodes="true" :options="udfResourceList" :disabled="isUpdate" :normalizer="normalizer" :placeholder="$t('Please select UDF resources directory')">
|
<treeselect id="btnUdfResourceDropDown" style="width:535px;float:left;" v-model="resourceId" maxHeight="200" :disable-branch-nodes="true" :options="udfResourceList" :disabled="isUpdate" :normalizer="normalizer" :placeholder="$t('Please select UDF resources directory')">
|
||||||
<div class="options-udf-resource" slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
|
<div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
|
||||||
</treeselect>
|
</treeselect>
|
||||||
<el-button type="primary" size="small" @click="_toggleUpdate" :disabled="upDisabled">{{$t('Upload Resources')}}</el-button>
|
<el-button type="primary" size="small" @click="_toggleUpdate" :disabled="upDisabled">{{$t('Upload Resources')}}</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="list-model">
|
<div class="list-model">
|
||||||
<div class="table-box">
|
<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="udf-function-items">
|
||||||
<el-table-column type="index" :label="$t('#')" min-width="120"></el-table-column>
|
<el-table-column type="index" :label="$t('#')" min-width="120"></el-table-column>
|
||||||
<el-table-column :label="$t('UDF Function Name')">
|
<el-table-column :label="$t('UDF Function Name')">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
<el-table-column :label="$t('Operation')" min-width="100">
|
<el-table-column :label="$t('Operation')" min-width="100">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tooltip :content="$t('Rename')" placement="top" :enterable="false">
|
<el-tooltip :content="$t('Rename')" placement="top" :enterable="false">
|
||||||
<span><el-button type="primary" size="mini" icon="el-icon-edit-outline" @click="_edit(scope.row)" circle></el-button></span>
|
<span><el-button id="btnRename" type="primary" size="mini" icon="el-icon-edit-outline" @click="_edit(scope.row)" circle></el-button></span>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip :content="$t('Delete')" placement="top" :enterable="false">
|
<el-tooltip :content="$t('Delete')" placement="top" :enterable="false">
|
||||||
<el-popconfirm
|
<el-popconfirm
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
:title="$t('Delete?')"
|
:title="$t('Delete?')"
|
||||||
@onConfirm="_delete(scope.row,scope.row.id)"
|
@onConfirm="_delete(scope.row,scope.row.id)"
|
||||||
>
|
>
|
||||||
<el-button type="danger" size="mini" icon="el-icon-delete" circle slot="reference"></el-button>
|
<el-button id="btnDelete" type="danger" size="mini" icon="el-icon-delete" circle slot="reference"></el-button>
|
||||||
</el-popconfirm>
|
</el-popconfirm>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -64,6 +64,7 @@
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
|
id="createUdfDialog"
|
||||||
:visible.sync="createUdfDialog"
|
:visible.sync="createUdfDialog"
|
||||||
width="auto">
|
width="auto">
|
||||||
<m-create-udf :item="item" @onUpdate="onUpdate" @close="close"></m-create-udf>
|
<m-create-udf :item="item" @onUpdate="onUpdate" @close="close"></m-create-udf>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
<m-conditions @on-conditions="_onConditions">
|
<m-conditions @on-conditions="_onConditions">
|
||||||
<template slot="button-group">
|
<template slot="button-group">
|
||||||
<el-button-group>
|
<el-button-group>
|
||||||
<el-button size="mini" @click="_create">{{$t('Create UDF Function')}}</el-button>
|
<el-button id="btnCreateUdfFunction" size="mini" @click="_create">{{$t('Create UDF Function')}}</el-button>
|
||||||
</el-button-group>
|
</el-button-group>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:visible.sync="createUdfDialog"
|
:visible.sync="createUdfDialog"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue