Skip to content

Commit

Permalink
[Feature] Introduce yarn queue e2e test (#3880)
Browse files Browse the repository at this point in the history
* [Future] Introduce yarn queue e2e test

* add e2e.yml

* Improve YarnQueueTest

---------

Co-authored-by: benjobs <[email protected]>
  • Loading branch information
zzzk1 and wolfboys authored Jul 18, 2024
1 parent e7d33b6 commit 2fd2084
Show file tree
Hide file tree
Showing 5 changed files with 323 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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));
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

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;
Expand Down Expand Up @@ -86,6 +87,17 @@ public <T extends NavBarItem> T goToNav(Class<T> nav) {
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");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}

0 comments on commit 2fd2084

Please sign in to comment.