From 4b58df9aa80a24f7f22529b1a92a2ea043d648b5 Mon Sep 17 00:00:00 2001 From: xiangzihao <460888207@qq.com> Date: Sun, 30 Jan 2022 09:01:19 +0800 Subject: [PATCH] [E2E] add function manage test case (#8250) --- .github/workflows/e2e.yml | 2 + .../e2e/cases/FunctionManageE2ETest.java | 187 ++++++++++++++++++ .../pages/resource/FunctionManagePage.java | 143 ++++++++++++++ .../udf/pages/function/_source/createUdf.vue | 2 +- .../pages/udf/pages/function/_source/list.vue | 7 +- .../pages/udf/pages/function/index.vue | 2 +- 6 files changed, 338 insertions(+), 5 deletions(-) create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FunctionManageE2ETest.java diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index f7579efb1e..118bf77237 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -87,6 +87,8 @@ jobs: class: org.apache.dolphinscheduler.e2e.cases.FileManageE2ETest - name: UdfManage class: org.apache.dolphinscheduler.e2e.cases.UdfManageE2ETest + - name: FunctionManage + class: org.apache.dolphinscheduler.e2e.cases.FunctionManageE2ETest - name: MysqlDataSource class: org.apache.dolphinscheduler.e2e.cases.MysqlDataSourceE2ETest - name: ClickhouseDataSource diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FunctionManageE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FunctionManageE2ETest.java new file mode 100644 index 0000000000..c0e14b02b5 --- /dev/null +++ b/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) + ); + }); + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FunctionManagePage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FunctionManagePage.java index 6934e9e2f6..b0800dc72f 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FunctionManagePage.java +++ b/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 java.util.List; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; 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 public class FunctionManagePage extends NavBarPage implements ResourcePage.Tab { + @FindBy(id = "btnCreateUdfFunction") + private WebElement buttonCreateUdfFunction; + + @FindBy(className = "udf-function-items") + private List functionList; + + @FindBys({ + @FindBy(className = "el-popconfirm"), + @FindBy(className = "el-button--primary"), + }) + private List buttonConfirm; + + private final CreateUdfFunctionBox createUdfFunctionBox; + + private final RenameUdfFunctionBox renameUdfFunctionBox; + public FunctionManagePage(RemoteWebDriver 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 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; } } diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue index ed4632e8eb..c5b5f8cf86 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue @@ -57,7 +57,7 @@ diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/list.vue index 34250ef734..d7e85336bc 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/list.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/list.vue @@ -17,7 +17,7 @@