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

benjobs pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampark.git


The following commit(s) were added to refs/heads/dev by this push:
     new 2fd2084ce [Feature] Introduce yarn queue e2e test (#3880)
2fd2084ce is described below

commit 2fd2084ce370911bcaa8420194740c9a48139440
Author: Zhengke Zhou <[email protected]>
AuthorDate: Thu Jul 18 17:55:58 2024 +0800

    [Feature] Introduce yarn queue e2e test (#3880)
    
    * [Future] Introduce yarn queue e2e test
    
    * add e2e.yml
    
    * Improve YarnQueueTest
    
    ---------
    
    Co-authored-by: benjobs <[email protected]>
---
 .github/workflows/e2e.yml                          |   2 +
 .../apache/streampark/e2e/cases/YarnQueueTest.java | 119 ++++++++++++++++++
 .../streampark/e2e/pages/common/NavBarPage.java    |  12 ++
 .../streampark/e2e/pages/setting/SettingPage.java  |  54 ++++++++
 .../e2e/pages/setting/YarnQueuePage.java           | 136 +++++++++++++++++++++
 5 files changed, 323 insertions(+)

diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index ec81ff7dd..bae475568 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -110,6 +110,8 @@ jobs:
     strategy:
       matrix:
         case:
+          - name: YarnQueueTest
+            class: org.apache.streampark.e2e.cases.YarnQueueTest
           - name: TokenManagementTest
             class: org.apache.streampark.e2e.cases.TokenManagementTest
           - name: UploadManagementTest
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/cases/YarnQueueTest.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/cases/YarnQueueTest.java
new file mode 100644
index 000000000..c649808b4
--- /dev/null
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/cases/YarnQueueTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.streampark.e2e.cases;
+
+import org.apache.streampark.e2e.core.StreamPark;
+import org.apache.streampark.e2e.pages.LoginPage;
+import org.apache.streampark.e2e.pages.setting.SettingPage;
+import org.apache.streampark.e2e.pages.setting.YarnQueuePage;
+
+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 org.testcontainers.shaded.org.awaitility.Awaitility;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@StreamPark(composeFiles = "docker/basic/docker-compose.yaml")
+public class YarnQueueTest {
+
+    private static RemoteWebDriver browser;
+
+    private static final String userName = "admin";
+
+    private static final String password = "streampark";
+
+    private static final String teamName = "default";
+
+    private static final String newQueueLabel = "new_label";
+
+    private static final String editQueueLabel = "edit_label";
+
+    private static final String description = "test_description";
+
+    @BeforeAll
+    public static void setup() {
+        new LoginPage(browser)
+            .login(userName, password, teamName)
+            .goToNav(SettingPage.class)
+            .goToTab(YarnQueuePage.class);
+    }
+
+    @Test
+    @Order(10)
+    void testYarnQueue() {
+        final YarnQueuePage queuePage = new YarnQueuePage(browser);
+        queuePage.createYarnQueue(newQueueLabel, description);
+
+        Awaitility.await()
+            .untilAsserted(
+                () -> assertThat(queuePage.yarnQueueList())
+                    .as("Yarn Queue list should contain newly-created item")
+                    .extracting(WebElement::getText)
+                    .anyMatch(it -> it.contains(newQueueLabel))
+                    .anyMatch(it -> it.contains(description)));
+    }
+
+    @Test
+    @Order(20)
+    void testCreateDuplicateYarnQueue() {
+        final YarnQueuePage queuePage = new YarnQueuePage(browser);
+        queuePage.createYarnQueue(newQueueLabel, description);
+        Awaitility.await()
+            .untilAsserted(
+                () -> assertThat(queuePage.errorMessageList())
+                    .as("Yarn Queue Duplicated Error message should be 
displayed")
+                    .extracting(WebElement::getText)
+                    .anyMatch(it -> it.contains("The queue label existed in 
the current team")));
+
+        queuePage.createYarnQueueForm().buttonCancel().click();
+    }
+
+    @Test
+    @Order(30)
+    void testEditYarnQueue() {
+        final YarnQueuePage queuePage = new YarnQueuePage(browser);
+        String editDescription = "edit_" + description;
+
+        queuePage.editYarnQueue(newQueueLabel, editQueueLabel, 
editDescription);
+
+        Awaitility.await()
+            .untilAsserted(
+                () -> assertThat(queuePage.yarnQueueList())
+                    .as("Yarn queue list should contain edited yarn queue")
+                    .extracting(WebElement::getText)
+                    .anyMatch(it -> it.contains(editQueueLabel))
+                    .anyMatch(it -> it.contains(editDescription)));
+    }
+
+    @Test
+    @Order(40)
+    void testDeleteYarnQueue() {
+        final YarnQueuePage queuePage = new YarnQueuePage(browser);
+
+        queuePage.deleteYarnQueue(editQueueLabel);
+        Awaitility.await()
+            .untilAsserted(
+                () -> {
+                    assertThat(queuePage.yarnQueueList())
+                        .noneMatch(it -> 
it.getText().contains(editQueueLabel));
+                });
+    }
+}
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/common/NavBarPage.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/common/NavBarPage.java
index 4b7dc1cdb..d8a0ae961 100644
--- 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/common/NavBarPage.java
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/common/NavBarPage.java
@@ -19,6 +19,7 @@ package org.apache.streampark.e2e.pages.common;
 
 import org.apache.streampark.e2e.pages.flink.ApacheFlinkPage;
 import org.apache.streampark.e2e.pages.resource.ResourcePage;
+import org.apache.streampark.e2e.pages.setting.SettingPage;
 import org.apache.streampark.e2e.pages.system.SystemPage;
 
 import lombok.Getter;
@@ -86,6 +87,17 @@ public class NavBarPage {
             return nav.cast(new ResourcePage(driver));
         }
 
+        if (nav == SettingPage.class) {
+            new WebDriverWait(driver, 
Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+                .until(ExpectedConditions.elementToBeClickable(settingsTab));
+            String tabOpenStateXpath =
+                "//span[contains(@class, 'ml-2') and contains(@class, 
'streampark-simple-menu-sub-title') and contains(text(), 
'Settings')]/../parent::li[contains(@class, 'streampark-menu-opened')]";
+            if (driver.findElements(By.xpath(tabOpenStateXpath)).isEmpty()) {
+                settingsTab.click();
+            }
+            return nav.cast(new SettingPage(driver));
+        }
+
         throw new UnsupportedOperationException("Unknown nav bar");
     }
 
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/SettingPage.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/SettingPage.java
new file mode 100644
index 000000000..188319162
--- /dev/null
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/SettingPage.java
@@ -0,0 +1,54 @@
+/*
+ * 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.streampark.e2e.pages.setting;
+
+import org.apache.streampark.e2e.pages.common.NavBarPage;
+
+import lombok.Getter;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.remote.RemoteWebDriver;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.time.Duration;
+
+@Getter
+public class SettingPage extends NavBarPage implements NavBarPage.NavBarItem {
+
+    @FindBy(xpath = "//span[contains(@class, 
'streampark-simple-menu-sub-title') and contains(text(), 'Yarn Queue')]//..")
+    private WebElement menuYarnQueueManagement;
+
+    public SettingPage(RemoteWebDriver driver) {
+        super(driver);
+    }
+
+    public <T extends SettingPage.Tab> T goToTab(Class<T> tab) {
+        if (tab == YarnQueuePage.class) {
+            new WebDriverWait(driver, Duration.ofSeconds(10))
+                
.until(ExpectedConditions.elementToBeClickable(menuYarnQueueManagement));
+            menuYarnQueueManagement.click();
+            return tab.cast(new YarnQueuePage(driver));
+        }
+
+        throw new UnsupportedOperationException("Unknown tab: " + 
tab.getName());
+    }
+
+    public interface Tab {
+    }
+}
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/YarnQueuePage.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/YarnQueuePage.java
new file mode 100644
index 000000000..6b25b3af8
--- /dev/null
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/YarnQueuePage.java
@@ -0,0 +1,136 @@
+/*
+ * 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.streampark.e2e.pages.setting;
+
+import org.apache.streampark.e2e.pages.common.Constants;
+import org.apache.streampark.e2e.pages.common.NavBarPage;
+
+import lombok.Getter;
+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.PageFactory;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.util.List;
+
+@Getter
+public class YarnQueuePage extends NavBarPage implements SettingPage.Tab {
+
+    @FindBy(xpath = "//span[contains(., 'Yarn Queue 
List')]/..//button[contains(@class, 'ant-btn-primary')]/span[contains(text(), 
'Add New')]")
+    private WebElement buttonCreateYarnQueue;
+
+    @FindBy(xpath = "//tbody[contains(@class, 'ant-table-tbody')]")
+    private List<WebElement> yarnQueueList;
+
+    @FindBy(className = "ant-form-item-explain-error")
+    private List<WebElement> errorMessageList;
+
+    @FindBy(xpath = "//button[contains(@class, 'ant-btn')]/span[contains(., 
'OK')]")
+    private WebElement deleteConfirmButton;
+
+    private final CreateYarnQueueForm createYarnQueueForm = new 
CreateYarnQueueForm();
+
+    public YarnQueuePage(RemoteWebDriver driver) {
+        super(driver);
+    }
+
+    public YarnQueuePage createYarnQueue(String queueLabel, String 
description) {
+        waitForPageLoading();
+
+        new WebDriverWait(driver, Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+            
.until(ExpectedConditions.elementToBeClickable(buttonCreateYarnQueue));
+        buttonCreateYarnQueue.click();
+
+        createYarnQueueForm.inputQueueLabel.sendKeys(queueLabel);
+        createYarnQueueForm.inputDescription.sendKeys(description);
+
+        createYarnQueueForm.buttonOk().click();
+        return this;
+    }
+
+    public YarnQueuePage editYarnQueue(String queueLabel, String 
editQueueLabel, String description) {
+        waitForPageLoading();
+
+        yarnQueueList().stream()
+            .filter(it -> it.getText().contains(queueLabel))
+            .flatMap(
+                it -> it.findElements(By.xpath(".//button[contains(@tooltip, 
'Edit')]")).stream())
+            .filter(WebElement::isDisplayed)
+            .findFirst()
+            .orElseThrow(() -> new RuntimeException("No edit button in yarn 
queue list"))
+            .click();
+
+        new WebDriverWait(driver, Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+            
.until(ExpectedConditions.elementToBeClickable(createYarnQueueForm.buttonOk));
+        createYarnQueueForm.inputQueueLabel().clear();
+        createYarnQueueForm.inputQueueLabel().sendKeys(editQueueLabel);
+        createYarnQueueForm.inputDescription().clear();
+        createYarnQueueForm.inputDescription().sendKeys(description);
+
+        createYarnQueueForm.buttonOk().click();
+        return this;
+    }
+
+    public YarnQueuePage deleteYarnQueue(String queueLabel) {
+        waitForPageLoading();
+
+        yarnQueueList().stream()
+            .filter(it -> it.getText().contains(queueLabel))
+            .flatMap(
+                it -> it.findElements(By.xpath(".//button[contains(@tooltip, 
'Delete')]")).stream())
+            .filter(WebElement::isDisplayed)
+            .findFirst()
+            .orElseThrow(() -> new RuntimeException("No delete button in yarn 
queue list"))
+            .click();
+
+        new WebDriverWait(driver, Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+            
.until(ExpectedConditions.elementToBeClickable(deleteConfirmButton));
+
+        deleteConfirmButton.click();
+
+        return this;
+    }
+
+    private void waitForPageLoading() {
+        new WebDriverWait(driver, Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+            .until(ExpectedConditions.urlContains("/setting/yarn-queue"));
+    }
+
+    @Getter
+    public class CreateYarnQueueForm {
+
+        CreateYarnQueueForm() {
+            PageFactory.initElements(driver, this);
+        }
+
+        @FindBy(id = "YarnQueueEditForm_queueLabel")
+        private WebElement inputQueueLabel;
+
+        @FindBy(id = "YarnQueueEditForm_description")
+        private WebElement inputDescription;
+
+        @FindBy(xpath = "//button[contains(@class, 
'ant-btn')]//span[contains(text(), 'OK')]")
+        private WebElement buttonOk;
+
+        @FindBy(xpath = "//button[contains(@class, 
'ant-btn')]//span[contains(text(), 'Cancel')]")
+        private WebElement buttonCancel;
+    }
+}

Reply via email to