Browse Source

[E2E] add function manage test case (#8250)

3.0.0/version-upgrade
xiangzihao 3 years ago committed by GitHub
parent
commit
4b58df9aa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/workflows/e2e.yml
  2. 187
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FunctionManageE2ETest.java
  3. 143
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FunctionManagePage.java
  4. 2
      dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue
  5. 7
      dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/list.vue
  6. 2
      dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/index.vue

2
.github/workflows/e2e.yml

@ -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

187
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FunctionManageE2ETest.java

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

143
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FunctionManagePage.java

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

2
dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue

@ -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>

7
dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/list.vue

@ -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>

2
dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/index.vue

@ -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…
Cancel
Save