From 30b8b4a93ea1bda25de3ab0ad6dcf685161e3da6 Mon Sep 17 00:00:00 2001 From: xiangzihao <460888207@qq.com> Date: Wed, 26 Jan 2022 09:45:21 +0800 Subject: [PATCH] [E2E][CI] Add renaming file management E2E tests (#8160) --- .../e2e/cases/FileManageE2ETest.java | 197 +++++++++++++++++- .../e2e/cases/MysqlDataSourceE2ETest.java | 2 + .../e2e/pages/resource/FileManagePage.java | 170 ++++++++++++++- .../dolphinscheduler/e2e/core/Constants.java | 51 +++++ .../e2e/core/DolphinSchedulerExtension.java | 26 +++ .../pages/file/pages/create/index.vue | 5 +- .../resource/pages/file/pages/edit/index.vue | 4 +- .../pages/file/pages/list/_source/list.vue | 6 +- .../pages/file/pages/list/_source/rename.vue | 2 + .../components/fileUpdate/fileUpdate.vue | 2 +- .../src/js/module/components/popup/popup.vue | 4 +- 11 files changed, 457 insertions(+), 12 deletions(-) create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/Constants.java 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 98bbada252..1a32b5e5d4 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 @@ -20,6 +20,7 @@ package org.apache.dolphinscheduler.e2e.cases; +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.FileManagePage; @@ -28,6 +29,7 @@ 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; @@ -38,6 +40,12 @@ import org.openqa.selenium.remote.RemoteWebDriver; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.file.Paths; +import java.util.Arrays; + @DolphinScheduler(composeFiles = "docker/file-manage/docker-compose.yaml") public class FileManageE2ETest { private static RemoteWebDriver browser; @@ -54,6 +62,20 @@ public class FileManageE2ETest { private static final String testDiretoryName = "test_directory"; + private static final String testSubDirectoryName = "test_sub_directory"; + + private static final String testRenameDirectoryName = "test_rename_directory"; + + private static final String testFileName = "test_file"; + + private static final String testRenameFileName = "test_rename_file.sh"; + + private static final String testUnder1GBFileName = "test_file_0.01G"; + + private static final String testOver1GBFilePath = Constants.HOST_TMP_PATH + "/test_file_1.5G"; + + private static final String testUnder1GBFilePath = Constants.HOST_TMP_PATH + "/" + testUnder1GBFileName; + @BeforeAll public static void setup() { TenantPage tenantPage = new LoginPage(browser) @@ -72,6 +94,21 @@ public class FileManageE2ETest { .goToTab(FileManagePage.class); } + @AfterAll + public static void cleanup() { + String[] command = {"/bin/bash", "-c", String.format("sudo rm -f %s && sudo rm -f %s && sudo rm -rf %s", testUnder1GBFilePath, testOver1GBFilePath, Constants.HOST_CHROME_DOWNLOAD_PATH)}; + + try { + Process pro = Runtime.getRuntime().exec(command); + int status = pro.waitFor(); + if (status != 0) { + throw new RuntimeException(String.format("Failed to call shell's command: %s", Arrays.toString(command))); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Test @Order(10) void testCreateDirectory() { @@ -85,6 +122,19 @@ public class FileManageE2ETest { .anyMatch(it -> it.contains(testDiretoryName))); } + @Test + @Order(11) + void testCancelCreateDirectory() { + final FileManagePage page = new FileManagePage(browser); + + page.cancelCreateDirectory(testDiretoryName, "test_desc"); + + await().untilAsserted(() -> assertThat(page.fileList()) + .as("File list should contain newly-created file") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(testDiretoryName))); + } + @Test @Order(20) void testCreateDuplicateDirectory() { @@ -99,12 +149,44 @@ public class FileManageE2ETest { page.createDirectoryBox().buttonCancel().click(); } + @Test + @Order(21) + void testCreateSubDirectory() { + final FileManagePage page = new FileManagePage(browser); + + page.createSubDirectory(testDiretoryName, testSubDirectoryName, "test_desc"); + + await().untilAsserted(() -> assertThat(page.fileList()) + .as("File list should contain newly-created file") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(testSubDirectoryName))); + } + + @Test + @Order(22) + void testRenameDirectory() { + final FileManagePage page = new FileManagePage(browser); + + page.rename(testSubDirectoryName, testRenameDirectoryName); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + + assertThat(page.fileList()) + .as("File list should contain newly-created file") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(testRenameDirectoryName)); + }); + } + @Test @Order(30) void testDeleteDirectory() { final FileManagePage page = new FileManagePage(browser); - page.delete(testDiretoryName); + page.goToNav(ResourcePage.class) + .goToTab(FileManagePage.class) + .delete(testDiretoryName); await().untilAsserted(() -> { browser.navigate().refresh(); @@ -116,4 +198,117 @@ public class FileManageE2ETest { ); }); } + + @Test + @Order(40) + void testCreateFile() { + final FileManagePage page = new FileManagePage(browser); + String scripts = "echo 123"; + + page.createFile(testFileName, scripts); + + await().untilAsserted(() -> assertThat(page.fileList()) + .as("File list should contain newly-created file") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(testFileName))); + } + + @Test + @Order(41) + void testRenameFile() { + final FileManagePage page = new FileManagePage(browser); + + page.rename(testFileName, testRenameFileName); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + + assertThat(page.fileList()) + .as("File list should contain newly-created file") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(testRenameFileName)); + }); + } + + @Test + @Order(42) + void testEditFile() { + final FileManagePage page = new FileManagePage(browser); + String scripts = "echo 456"; + + page.editFile(testRenameFileName, scripts); + + await().untilAsserted(() -> assertThat(page.fileList()) + .as("File list should contain newly-created file") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(testRenameFileName))); + } + + @Test + @Order(45) + void testDeleteFile() { + final FileManagePage page = new FileManagePage(browser); + + page.delete(testRenameFileName); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + + assertThat( + page.fileList() + ).noneMatch( + it -> it.getText().contains(testRenameFileName) + ); + }); + } + + @Test + @Order(60) + void testUploadOver1GBFile() throws IOException { + final FileManagePage page = new FileManagePage(browser); + + RandomAccessFile file = new RandomAccessFile(testOver1GBFilePath, "rw"); + file.setLength((long) (1.5 * 1024 * 1024 * 1024)); + + page.uploadFile(testOver1GBFilePath); + + await().untilAsserted(() -> + assertThat(browser.findElement(By.tagName("body")).getText()) + .contains("Upload File size cannot exceed 1g") + ); + } + + @Test + @Order(65) + void testUploadUnder1GBFile() throws IOException { + final FileManagePage page = new FileManagePage(browser); + + browser.navigate().refresh(); + + RandomAccessFile file = new RandomAccessFile(testUnder1GBFilePath, "rw"); + file.setLength((long) (0.01 * 1024 * 1024 * 1024)); + + page.uploadFile(testUnder1GBFilePath); + + await().untilAsserted(() -> { + assertThat(page.fileList()) + .as("File list should contain newly-created file") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(testUnder1GBFileName)); + }); + } + + @Test + @Order(70) + void testDownloadFile() { + final FileManagePage page = new FileManagePage(browser); + + page.downloadFile(testUnder1GBFileName); + + File file = new File(Paths.get(Constants.HOST_CHROME_DOWNLOAD_PATH, testUnder1GBFileName).toFile().getAbsolutePath()); + + await().untilAsserted(() -> { + assert file.exists(); + }); + } } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/MysqlDataSourceE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/MysqlDataSourceE2ETest.java index 996a282715..6c28e7b591 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/MysqlDataSourceE2ETest.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/MysqlDataSourceE2ETest.java @@ -31,6 +31,7 @@ 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.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.support.ui.ExpectedConditions; @@ -105,4 +106,5 @@ public class MysqlDataSourceE2ETest { ); }); } + } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FileManagePage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FileManagePage.java index 08d931197d..9e5661d87c 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FileManagePage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FileManagePage.java @@ -22,16 +22,18 @@ package org.apache.dolphinscheduler.e2e.pages.resource; import lombok.Getter; +import org.apache.dolphinscheduler.e2e.pages.common.CodeEditor; import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; -import org.apache.dolphinscheduler.e2e.pages.security.TenantPage; 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; +import java.io.File; import java.util.List; @@ -40,8 +42,20 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab { @FindBy(id = "btnCreateDirectory") private WebElement buttonCreateDirectory; + @FindBy(id = "btnCreateFile") + private WebElement buttonCreateFile; + + @FindBy(id = "btnUploadFile") + private WebElement buttonUploadFile; + private final CreateDirectoryBox createDirectoryBox; + private final RenameDirectoryBox renameDirectoryBox; + + private final CreateFileBox createFileBox; + + private final UploadFileBox uploadFileBox; + @FindBy(className = "items") private List fileList; @@ -58,6 +72,12 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab { super(driver); createDirectoryBox = new CreateDirectoryBox(); + + renameDirectoryBox = new RenameDirectoryBox(); + + createFileBox = new CreateFileBox(); + + uploadFileBox = new UploadFileBox(); } public FileManagePage createDirectory(String name, String description) { @@ -70,6 +90,51 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab { return this; } + public FileManagePage cancelCreateDirectory(String name, String description) { + buttonCreateDirectory().click(); + + createDirectoryBox().inputDirectoryName().sendKeys(name); + createDirectoryBox().inputDescription().sendKeys(description); + createDirectoryBox().buttonCancel().click(); + + return this; + } + + public FileManagePage rename(String currentName, String AfterName) { + fileList() + .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 file manage list")) + .click(); + + renameDirectoryBox().inputName().clear(); + renameDirectoryBox().inputName().sendKeys(AfterName); + renameDirectoryBox().buttonSubmit().click(); + + return this; + } + + public FileManagePage createSubDirectory(String directoryName, String subDirectoryName, String description) { + fileList() + .stream() + .filter(it -> it.getText().contains(directoryName)) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException(String.format("No %s in file manage list", directoryName))) + .click(); + + buttonCreateDirectory().click(); + + createDirectoryBox().inputDirectoryName().sendKeys(subDirectoryName); + createDirectoryBox().inputDescription().sendKeys(description); + createDirectoryBox().buttonSubmit().click(); + + return this; + } + public FileManagePage delete(String name) { fileList() .stream() @@ -90,6 +155,56 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab { return this; } + public FileManagePage createFile(String fileName, String scripts) { + buttonCreateFile().click(); + + createFileBox().inputFileName().sendKeys(fileName); + createFileBox().codeEditor().content(scripts); + createFileBox().buttonSubmit().click(); + + return this; + } + + public FileManagePage editFile(String fileName, String scripts) { + fileList() + .stream() + .filter(it -> it.getText().contains(fileName)) + .flatMap(it -> it.findElements(By.id("btnEdit")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No edit button in file manage list")) + .click(); + + createFileBox().codeEditor().content(scripts); + createFileBox().buttonSubmit().click(); + + return this; + } + + public FileManagePage uploadFile(String filePath) { + buttonUploadFile().click(); + + driver.setFileDetector(new LocalFileDetector()); + + uploadFileBox().buttonUpload().sendKeys(filePath); + uploadFileBox().buttonSubmit().click(); + + return this; + } + + public FileManagePage downloadFile(String fileName) { + fileList() + .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 file manage list")) + .click(); + + return this; + } + @Getter public class CreateDirectoryBox { CreateDirectoryBox() { @@ -108,4 +223,57 @@ public class FileManagePage extends NavBarPage implements ResourcePage.Tab { @FindBy(id = "btnCancel") private WebElement buttonCancel; } + + @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 CreateFileBox { + CreateFileBox() { + PageFactory.initElements(driver, this); + } + + @FindBy(id = "inputFileName") + private WebElement inputFileName; + + private final CodeEditor codeEditor = new CodeEditor(driver); + + @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; + } } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/Constants.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/Constants.java new file mode 100644 index 0000000000..1852fa8869 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/Constants.java @@ -0,0 +1,51 @@ +/* + * 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.core; + +import java.nio.file.Paths; + +/** + * Constants + */ +public final class Constants { + + private Constants() { + throw new UnsupportedOperationException("Construct Constants"); + } + + /** + * tmp directory path + */ + public static final String HOST_TMP_PATH = System.getProperty("java.io.tmpdir"); + + /** + * chrome download path in host + */ + public static final String HOST_CHROME_DOWNLOAD_PATH = Paths.get(System.getProperty("java.io.tmpdir"), "download").toFile().getAbsolutePath(); + + /** + * chrome download path in selenium/standalone-chrome-debug container + */ + public static final String SELENIUM_CONTAINER_CHROME_DOWNLOAD_PATH = "/home/seluser/Downloads"; + + /** + * host os name + */ + public static final String OS_NAME = System.getProperties().getProperty("os.name"); + +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java index 518f9f62e3..0273df208f 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java @@ -31,6 +31,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -116,8 +117,33 @@ final class DolphinSchedulerExtension } else { record = Files.createTempDirectory("record-"); } + + // According to https://github.com/SeleniumHQ/docker-selenium#mounting-volumes-to-retrieve-downloaded-files + if ("linux".equalsIgnoreCase(Constants.OS_NAME)) { + File file = new File(Constants.HOST_CHROME_DOWNLOAD_PATH); + boolean result = file.mkdir(); + + if (!result) { + throw new IOException(String.format("mkdir %s error", Constants.HOST_CHROME_DOWNLOAD_PATH)); + } + + String[] command = {"/bin/bash", "-c", String.format("sudo chown 1200:1201 %s", Constants.HOST_CHROME_DOWNLOAD_PATH)}; + + try { + Process pro = Runtime.getRuntime().exec(command); + int status = pro.waitFor(); + if (status != 0) { + throw new IOException(String.format("Failed to call shell's command: %s", Arrays.toString(command))); + } + } catch (Exception e) { + throw new IOException(e); + } + + } + browser = new BrowserWebDriverContainer<>() .withCapabilities(new ChromeOptions()) + .withFileSystemBind(Constants.HOST_CHROME_DOWNLOAD_PATH, Constants.SELENIUM_CONTAINER_CHROME_DOWNLOAD_PATH) .withRecordingMode(RECORD_ALL, record.toFile(), MP4); if (network != null) { browser.withNetwork(network); diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue index 003e9eb20c..ef526e5f5a 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue @@ -22,6 +22,7 @@ diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/edit/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/edit/index.vue index e2e26c8b74..0156747d3b 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/edit/index.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/edit/index.vue @@ -27,8 +27,8 @@
- {{$t('Return')}} - {{spinnerLoading ? $t('Loading...') : $t('Save')}} + {{$t('Return')}} + {{spinnerLoading ? $t('Loading...') : $t('Save')}}
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue index 5f6806f458..321ee53e53 100755 --- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue @@ -54,13 +54,13 @@