You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by ke...@apache.org on 2022/01/30 01:01:29 UTC

[dolphinscheduler] branch dev updated: [E2E] add function manage test case (#8250)

This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new 4b58df9  [E2E] add function manage test case (#8250)
4b58df9 is described below

commit 4b58df9aa80a24f7f22529b1a92a2ea043d648b5
Author: xiangzihao <46...@qq.com>
AuthorDate: Sun Jan 30 09:01:19 2022 +0800

    [E2E] add function manage test case (#8250)
---
 .github/workflows/e2e.yml                          |   2 +
 .../e2e/cases/FunctionManageE2ETest.java           | 187 +++++++++++++++++++++
 .../e2e/pages/resource/FunctionManagePage.java     | 143 ++++++++++++++++
 .../pages/udf/pages/function/_source/createUdf.vue |   2 +-
 .../pages/udf/pages/function/_source/list.vue      |   7 +-
 .../resource/pages/udf/pages/function/index.vue    |   2 +-
 6 files changed, 338 insertions(+), 5 deletions(-)

diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index f7579ef..118bf77 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 0000000..c0e14b0
--- /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 6934e9e..b0800dc 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<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) {
         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;
     }
 }
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 ed4632e..c5b5f8c 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 @@
           <template slot="name"><strong>*</strong>{{$t('UDF Resources')}}</template>
           <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')">
-              <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>
             <el-button type="primary" size="small" @click="_toggleUpdate" :disabled="upDisabled">{{$t('Upload Resources')}}</el-button>
           </template>
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 34250ef..d7e8533 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 @@
 <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="udf-function-items">
         <el-table-column type="index" :label="$t('#')" min-width="120"></el-table-column>
         <el-table-column :label="$t('UDF Function Name')">
           <template slot-scope="scope">
@@ -45,7 +45,7 @@
         <el-table-column :label="$t('Operation')" min-width="100">
           <template slot-scope="scope">
             <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 :content="$t('Delete')" placement="top" :enterable="false">
               <el-popconfirm
@@ -56,7 +56,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 id="btnDelete" type="danger" size="mini" icon="el-icon-delete" circle slot="reference"></el-button>
               </el-popconfirm>
             </el-tooltip>
           </template>
@@ -64,6 +64,7 @@
       </el-table>
     </div>
     <el-dialog
+      id="createUdfDialog"
       :visible.sync="createUdfDialog"
       width="auto">
       <m-create-udf :item="item" @onUpdate="onUpdate" @close="close"></m-create-udf>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/index.vue
index 250e9d9..f6efaa6 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/index.vue
@@ -20,7 +20,7 @@
       <m-conditions @on-conditions="_onConditions">
         <template slot="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-dialog
             :visible.sync="createUdfDialog"