diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index e7255acdea..f7579efb1e 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -85,6 +85,8 @@ jobs: class: org.apache.dolphinscheduler.e2e.cases.WorkflowE2ETest - name: FileManage class: org.apache.dolphinscheduler.e2e.cases.FileManageE2ETest + - name: UdfManage + class: org.apache.dolphinscheduler.e2e.cases.UdfManageE2ETest - 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/FileManageE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java index e9e708cf3a..5815d8cb59 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java @@ -66,7 +66,7 @@ public class FileManageE2ETest { private static final String phone = "15800000000"; - private static final String testDiretoryName = "test_directory"; + private static final String testDirectoryName = "test_directory"; private static final String testSubDirectoryName = "test_sub_directory"; @@ -116,12 +116,12 @@ public class FileManageE2ETest { void testCreateDirectory() { final FileManagePage page = new FileManagePage(browser); - page.createDirectory(testDiretoryName, "test_desc"); + page.createDirectory(testDirectoryName, "test_desc"); await().untilAsserted(() -> assertThat(page.fileList()) .as("File list should contain newly-created file") .extracting(WebElement::getText) - .anyMatch(it -> it.contains(testDiretoryName))); + .anyMatch(it -> it.contains(testDirectoryName))); } @Test @@ -129,12 +129,12 @@ public class FileManageE2ETest { void testCancelCreateDirectory() { final FileManagePage page = new FileManagePage(browser); - page.cancelCreateDirectory(testDiretoryName, "test_desc"); + page.cancelCreateDirectory(testDirectoryName, "test_desc"); await().untilAsserted(() -> assertThat(page.fileList()) .as("File list should contain newly-created file") .extracting(WebElement::getText) - .anyMatch(it -> it.contains(testDiretoryName))); + .anyMatch(it -> it.contains(testDirectoryName))); } @Test @@ -142,7 +142,7 @@ public class FileManageE2ETest { void testCreateDuplicateDirectory() { final FileManagePage page = new FileManagePage(browser); - page.createDirectory(testDiretoryName, "test_desc"); + page.createDirectory(testDirectoryName, "test_desc"); await().untilAsserted(() -> assertThat(browser.findElement(By.tagName("body")).getText()) .contains("resource already exists") @@ -156,7 +156,7 @@ public class FileManageE2ETest { void testCreateSubDirectory() { final FileManagePage page = new FileManagePage(browser); - page.createSubDirectory(testDiretoryName, testSubDirectoryName, "test_desc"); + page.createSubDirectory(testDirectoryName, testSubDirectoryName, "test_desc"); await().untilAsserted(() -> assertThat(page.fileList()) .as("File list should contain newly-created file") @@ -188,7 +188,7 @@ public class FileManageE2ETest { page.goToNav(ResourcePage.class) .goToTab(FileManagePage.class) - .delete(testDiretoryName); + .delete(testDirectoryName); await().untilAsserted(() -> { browser.navigate().refresh(); @@ -196,7 +196,7 @@ public class FileManageE2ETest { assertThat( page.fileList() ).noneMatch( - it -> it.getText().contains(testDiretoryName) + it -> it.getText().contains(testDirectoryName) ); }); } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UdfManageE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UdfManageE2ETest.java new file mode 100644 index 0000000000..1c9a878c1c --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UdfManageE2ETest.java @@ -0,0 +1,225 @@ +/* + * 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.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 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.WebElement; +import org.openqa.selenium.remote.RemoteWebDriver; + +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.nio.file.Paths; +import java.util.Comparator; +import java.util.Objects; + +@DolphinScheduler(composeFiles = "docker/file-manage/docker-compose.yaml") +public class UdfManageE2ETest { + 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 testDirectoryName = "test_directory"; + + private static final String testRenameDirectoryName = "test_rename_directory"; + + private static final String testUploadUdfFileName = "hive-jdbc-3.1.2.jar"; + + private static final Path testUploadUdfFilePath = Constants.HOST_TMP_PATH.resolve(testUploadUdfFileName); + + private static final String testUploadUdfRenameFileName = "hive-jdbc.jar"; + + @BeforeAll + 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))); + + tenantPage.goToNav(SecurityPage.class) + .goToTab(UserPage.class) + .update(user, user, password, email, phone) + .goToNav(ResourcePage.class) + .goToTab(UdfManagePage.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); + } + + @Test + @Order(10) + void testCreateDirectory() { + final UdfManagePage page = new UdfManagePage(browser); + + browser.navigate().refresh(); + + page.createDirectory(testDirectoryName, "test_desc"); + + await().untilAsserted(() -> assertThat(page.udfList()) + .as("File list should contain newly-created file") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(testDirectoryName))); + } + + @Test + @Order(20) + void testRenameDirectory() { + final UdfManagePage page = new UdfManagePage(browser); + + page.rename(testDirectoryName, testRenameDirectoryName); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + + assertThat(page.udfList()) + .as("File list should contain newly-created file") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(testRenameDirectoryName)); + }); + } + + @Test + @Order(30) + void testDeleteDirectory() { + final UdfManagePage page = new UdfManagePage(browser); + + page.delete(testRenameDirectoryName); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + + assertThat( + page.udfList() + ).noneMatch( + it -> it.getText().contains(testRenameDirectoryName) + ); + }); + } + + @Test + @Order(40) + @SneakyThrows + void testUploadUdf() { + final UdfManagePage page = new UdfManagePage(browser); + + downloadFile("https://repo1.maven.org/maven2/org/apache/hive/hive-jdbc/3.1.2/hive-jdbc-3.1.2.jar", testUploadUdfFilePath.toFile().getAbsolutePath()); + + page.uploadFile(testUploadUdfFilePath.toFile().getAbsolutePath()); + + await().untilAsserted(() -> { + assertThat(page.udfList()) + .as("File list should contain newly-created file") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(testUploadUdfFileName)); + }); + } + + 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(60) + void testRenameUdf() { + final UdfManagePage page = new UdfManagePage(browser); + + page.rename(testUploadUdfFileName, testUploadUdfRenameFileName); + + await().untilAsserted(() -> { + assertThat(page.udfList()) + .as("File list should contain newly-created file") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(testUploadUdfRenameFileName)); + }); + } + + @Test + @Order(70) + void testDeleteUdf() { + final UdfManagePage page = new UdfManagePage(browser); + + page.delete(testUploadUdfRenameFileName); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + + assertThat( + page.udfList() + ).noneMatch( + it -> it.getText().contains(testUploadUdfRenameFileName) + ); + }); + } +} 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 new file mode 100644 index 0000000000..6934e9e2f6 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FunctionManagePage.java @@ -0,0 +1,34 @@ +/* + * 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.pages.resource; + +import lombok.Getter; + +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; + +import org.openqa.selenium.remote.RemoteWebDriver; + +@Getter +public class FunctionManagePage extends NavBarPage implements ResourcePage.Tab { + public FunctionManagePage(RemoteWebDriver driver) { + super(driver); + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java index 0e9ee74565..7fc207b4de 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java @@ -33,7 +33,13 @@ import org.openqa.selenium.support.ui.WebDriverWait; @Getter public class ResourcePage extends NavBarPage implements NavBarPage.NavBarItem { @FindBy(className = "tab-file-manage") - private WebElement fileMagageManage; + private WebElement fileManageTab; + + @FindBy(className = "tab-udf-resource-manage") + private WebElement udfManageTab; + + @FindBy(className = "tab-function-resource-manage") + private WebElement functionManageTab; public ResourcePage(RemoteWebDriver driver) { super(driver); @@ -41,10 +47,23 @@ public class ResourcePage extends NavBarPage implements NavBarPage.NavBarItem { public T goToTab(Class tab) { if (tab == FileManagePage.class) { - WebElement fileMagageManageElement = new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(fileMagageManage)); - fileMagageManageElement.click(); + WebElement fileManageTabElement = new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(fileManageTab)); + fileManageTabElement.click(); return tab.cast(new FileManagePage(driver)); } + + if (tab == UdfManagePage.class) { + WebElement udfManageTabElement = new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(udfManageTab)); + udfManageTabElement.click(); + return tab.cast(new UdfManagePage(driver)); + } + + if (tab == FunctionManagePage.class) { + WebElement functionManageTabElement = new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(functionManageTab)); + functionManageTabElement.click(); + return tab.cast(new FunctionManagePage(driver)); + } + throw new UnsupportedOperationException("Unknown tab: " + tab.getName()); } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/UdfManagePage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/UdfManagePage.java new file mode 100644 index 0000000000..ae867e1c5d --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/UdfManagePage.java @@ -0,0 +1,194 @@ +/* + * 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.pages.resource; + +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.LocalFileDetector; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.FindBys; +import org.openqa.selenium.support.PageFactory; + +@Getter +public class UdfManagePage extends NavBarPage implements ResourcePage.Tab { + @FindBy(id = "btnCreateDirectory") + private WebElement buttonCreateDirectory; + + @FindBy(id = "btnUploadUdf") + private WebElement buttonUploadUdf; + + @FindBy(className = "udf-items") + private List udfList; + + @FindBys({ + @FindBy(className = "el-popconfirm"), + @FindBy(className = "el-button--primary"), + }) + private List buttonConfirm; + + private final UploadFileBox uploadFileBox; + + private final RenameDirectoryBox renameDirectoryBox; + + private final CreateDirectoryBox createDirectoryBox; + + public UdfManagePage(RemoteWebDriver driver) { + super(driver); + + uploadFileBox = new UploadFileBox(); + + renameDirectoryBox = new RenameDirectoryBox(); + + createDirectoryBox = new CreateDirectoryBox(); + } + + public UdfManagePage createDirectory(String name, String description) { + buttonCreateDirectory().click(); + + createDirectoryBox().inputDirectoryName().sendKeys(name); + createDirectoryBox().inputDescription().sendKeys(description); + createDirectoryBox().buttonSubmit().click(); + + return this; + } + + public UdfManagePage uploadFile(String filePath) { + buttonUploadUdf().click(); + + driver.setFileDetector(new LocalFileDetector()); + + uploadFileBox().buttonUpload().sendKeys(filePath); + uploadFileBox().buttonSubmit().click(); + + return this; + } + + public UdfManagePage downloadFile(String fileName) { + udfList() + .stream() + .filter(it -> it.getText().contains(fileName)) + .flatMap(it -> it.findElements(By.id("btnDownload")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No download button in udf manage list")) + .click(); + + return this; + } + + public UdfManagePage rename(String currentName, String AfterName) { + udfList() + .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 udf manage list")) + .click(); + + renameDirectoryBox().inputName().clear(); + renameDirectoryBox().inputName().sendKeys(AfterName); + renameDirectoryBox().buttonSubmit().click(); + + return this; + } + + public UdfManagePage delete(String name) { + udfList() + .stream() + .filter(it -> it.getText().contains(name)) + .flatMap(it -> it.findElements(By.id("btnDelete")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No delete button in udf manage list")) + .click(); + + buttonConfirm() + .stream() + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No confirm button when deleting")) + .click(); + + return this; + } + + @Getter + public class RenameDirectoryBox { + RenameDirectoryBox() { + PageFactory.initElements(driver, this); + } + + @FindBy(id = "inputName") + private WebElement inputName; + + @FindBy(id = "inputDescription") + private WebElement inputDescription; + + @FindBy(id = "btnSubmit") + private WebElement buttonSubmit; + + @FindBy(id = "btnCancel") + private WebElement buttonCancel; + } + + @Getter + public class UploadFileBox { + UploadFileBox() { + PageFactory.initElements(driver, this); + } + + @FindBy(id = "btnUpload") + private WebElement buttonUpload; + + @FindBy(id = "btnSubmit") + private WebElement buttonSubmit; + + @FindBy(id = "btnCancel") + private WebElement buttonCancel; + } + + @Getter + public class CreateDirectoryBox { + CreateDirectoryBox() { + PageFactory.initElements(driver, this); + } + + @FindBy(id = "inputDirectoryName") + private WebElement inputDirectoryName; + + @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/createUdfFolder/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/createUdfFolder/index.vue index c864d65e4a..a6ed93fca7 100755 --- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/createUdfFolder/index.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/createUdfFolder/index.vue @@ -22,6 +22,7 @@ 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 e1d9946fc9..ed4632e8eb 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 @@ -31,6 +31,7 @@