diff --git a/e2e/gui/src/test/java/com/epam/pipeline/autotests/LaunchParametersRestrictionRunsTest.java b/e2e/gui/src/test/java/com/epam/pipeline/autotests/LaunchParametersRestrictionRunsTest.java new file mode 100644 index 0000000000..0a474b8876 --- /dev/null +++ b/e2e/gui/src/test/java/com/epam/pipeline/autotests/LaunchParametersRestrictionRunsTest.java @@ -0,0 +1,410 @@ +/* + * Copyright 2017-2023 EPAM Systems, Inc. (https://www.epam.com/) + * + * Licensed 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 com.epam.pipeline.autotests; + +import com.epam.pipeline.autotests.ao.RunsMenuAO; +import com.epam.pipeline.autotests.ao.ToolSettings; +import com.epam.pipeline.autotests.ao.ToolTab; +import com.epam.pipeline.autotests.mixins.Authorization; +import com.epam.pipeline.autotests.mixins.Navigation; +import com.epam.pipeline.autotests.utils.C; +import com.epam.pipeline.autotests.utils.TestCase; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.IntStream; + +import static com.codeborne.selenide.Condition.*; +import static com.codeborne.selenide.Selectors.byText; +import static com.codeborne.selenide.Selenide.open; +import static com.epam.pipeline.autotests.ao.Primitive.EXEC_ENVIRONMENT; +import static com.epam.pipeline.autotests.ao.Primitive.SAVE; +import static com.epam.pipeline.autotests.utils.Utils.ON_DEMAND; +import static com.epam.pipeline.autotests.utils.Utils.nameWithoutGroup; +import static java.lang.Integer.parseInt; +import static java.lang.String.format; + +public class LaunchParametersRestrictionRunsTest + extends AbstractSeveralPipelineRunningTest + implements Navigation, Authorization { + + private final String LAUNCH_MAX_RUNS_USER_GLOBAL = "launch.max.runs.user.global"; + private final String ALLOWED_INSTANCES_MAX_COUNT = "Allowed instance max count"; + private final String USER_LIMIT = ""; + private final String GLOBAL_LIMIT = ""; + private final String registry = C.DEFAULT_REGISTRY; + private final String group = C.DEFAULT_GROUP; + private final String tool = C.TESTING_TOOL_NAME; + private final String USER_GROUP = C.ROLE_USER; + private final String GLOBAL_MAX_RUNS = "3"; + private final String GROUP_MAX_RUNS1 = "2"; + private final String GROUP_MAX_RUNS2 = "4"; + private final String USER_MAX_RUNS = "3"; + private final String USER_GROUP2 = "TEST_GROUP_2642"; + private String[] launchMaxRunsUserGlobalInitial; + private final String warningMessage = "You have exceeded maximum number of running jobs (%s)."; + private final String autoScaledClusterWarning = "Your cluster configuration may exceed the maximum " + + "number of running jobs. There %s running out of %s."; + private String launchErrorMessage = "Launch of new jobs is restricted as [%s] user " + + "will exceed [%s] runs limit [%s]"; + private final String runToolCommand = format("pipe run -di %s:latest -y", tool); + private final String[] runID3 = new String[2]; + private final List runID5 = new ArrayList<>(); + + @BeforeClass(alwaysRun = true) + public void getPreferences() { + launchMaxRunsUserGlobalInitial = navigationMenu() + .settings() + .switchToPreferences() + .getPreference(LAUNCH_MAX_RUNS_USER_GLOBAL); + setGroupAllowedInstanceMaxCount(USER_GROUP, StringUtils.EMPTY); + setUserAllowedInstanceMaxCount(user, StringUtils.EMPTY); + navigationMenu() + .settings() + .switchToUserManagement() + .switchToGroups() + .createGroupIfNoPresent(USER_GROUP2) + .editGroup(USER_GROUP2) + .addUser(user) + .ok(); + setGroupAllowedInstanceMaxCount(USER_GROUP2, StringUtils.EMPTY); + } + + @BeforeMethod + private void refreshPage() { + open(C.ROOT_ADDRESS); + logout(); + loginAs(admin); + } + + @AfterClass(alwaysRun = true) + public void restorePreferences() { + logout(); + loginAs(admin); + navigationMenu() + .settings() + .switchToPreferences() + .setNumberPreference(LAUNCH_MAX_RUNS_USER_GLOBAL, launchMaxRunsUserGlobalInitial[0], true) + .saveIfNeeded(); + setGroupAllowedInstanceMaxCount(USER_GROUP, StringUtils.EMPTY); + setUserAllowedInstanceMaxCount(user, StringUtils.EMPTY); + navigationMenu() + .settings() + .switchToUserManagement() + .switchToGroups() + .deleteGroupIfPresent(USER_GROUP2); + } + + @Test(priority = 1) + @TestCase(value = {"2642_1"}) + public void checkGlobalRestrictionCountOfRunningInstances() { + final String message = format(launchErrorMessage, user.login, GLOBAL_LIMIT, GLOBAL_MAX_RUNS); + final List runIDs = new ArrayList<>(); + try { + navigationMenu() + .settings() + .switchToPreferences() + .setNumberPreference(LAUNCH_MAX_RUNS_USER_GLOBAL, GLOBAL_MAX_RUNS, true) + .saveIfNeeded(); + logout(); + loginAs(user); + runIDs.addAll(launchSeveralRuns(parseInt(GLOBAL_MAX_RUNS))); + launchToolWithError(GLOBAL_MAX_RUNS, format(warningMessage, GLOBAL_MAX_RUNS), message); + + logout(); + loginAs(admin); + runIDs.addAll(launchSeveralRuns(parseInt(GLOBAL_MAX_RUNS))); + tools() + .perform(registry, group, tool, ToolTab::runWithCustomSettings) + .expandTab(EXEC_ENVIRONMENT) + .ensure(byText(format(warningMessage, GLOBAL_MAX_RUNS)), not(visible)) + .checkLaunchMessage("message", + format(warningMessage, GLOBAL_MAX_RUNS), false) + .launch(this); + runIDs.add(getLastRunId()); + } finally { + logout(); + loginAs(admin); + runIDs.forEach(runID -> runsMenu().viewAvailableActiveRuns().stopRun(runID)); + } + } + + @Test(priority = 1, dependsOnMethods = "checkGlobalRestrictionCountOfRunningInstances") + @TestCase(value = {"2642_2"}) + public void checkRunningInstancesRestrictionAppliedToGroup() { + final List runIDs = new ArrayList<>(); + try { + setGroupAllowedInstanceMaxCount(USER_GROUP, GROUP_MAX_RUNS1); + logout(); + loginAs(user); + runIDs.addAll(launchSeveralRuns(parseInt(GROUP_MAX_RUNS1))); + launchToolWithError(GROUP_MAX_RUNS1, format(warningMessage, GROUP_MAX_RUNS1), + format(launchErrorMessage, user.login, USER_GROUP, GROUP_MAX_RUNS1)); + logout(); + loginAs(admin); + setGroupAllowedInstanceMaxCount(USER_GROUP, GROUP_MAX_RUNS2); + logout(); + loginAs(user); + runIDs.addAll(launchSeveralRuns(parseInt(GROUP_MAX_RUNS1))); + launchToolWithError(GROUP_MAX_RUNS1, format(warningMessage, GROUP_MAX_RUNS2), + format(launchErrorMessage, user.login, USER_GROUP, GROUP_MAX_RUNS2)); + } finally { + logout(); + loginAs(admin); + runIDs.forEach(runID -> runsMenu().viewAvailableActiveRuns().stopRun(runID)); + } + } + + @Test(priority = 1, dependsOnMethods = "checkRunningInstancesRestrictionAppliedToGroup") + @TestCase(value = {"2642_3"}) + public void checkSimultaneousApplyingTwoGroupLevelRunningInstancesRestrictions() { + setGroupAllowedInstanceMaxCount(USER_GROUP2, GROUP_MAX_RUNS1); + logout(); + loginAs(user); + tools() + .perform(registry, group, tool, ToolTab::runWithCustomSettings) + .setPriceType(ON_DEMAND) + .doNotMountStoragesSelect(true) + .launch(this); + runID3[0] = getLastRunId(); + tools().perform(registry, group, tool, tool -> tool.run(this)); + runID3[1] = getLastRunId(); + launchToolWithError(GROUP_MAX_RUNS1, format(warningMessage, GROUP_MAX_RUNS1), + format(launchErrorMessage, user.login, USER_GROUP2, GROUP_MAX_RUNS1)); + runsMenu() + .showLog(runID3[0]) + .waitForSshLink() + .ssh(shell -> shell + .waitUntilTextAppears(runID3[0]) + .execute(runToolCommand) + .assertPageAfterCommandContainsStrings(runToolCommand, + format(launchErrorMessage, user.login, USER_GROUP2, GROUP_MAX_RUNS1)) + .execute("pipe users instances") + .assertPageContains( + format("Active runs detected for a user: [%s: %s]", user.login, GROUP_MAX_RUNS1)) + .assertPageContains( + format("The following restriction applied on runs launching: [%s: %s]", USER_GROUP2, + GROUP_MAX_RUNS1)) + .close()); + runsMenu() + .pause(runID3[0], nameWithoutGroup(tool)) + .waitUntilResumeButtonAppear(runID3[0]) + .stopRun(runID3[1]); + } + + @Test(priority = 1, dependsOnMethods = "checkSimultaneousApplyingTwoGroupLevelRunningInstancesRestrictions") + @TestCase(value = {"2642_4"}) + public void checkRunningInstancesRestrictionAppliedToUser() { + final List runIDs = new ArrayList<>(); + try { + setUserAllowedInstanceMaxCount(user, USER_MAX_RUNS); + logout(); + loginAs(user); + runIDs.addAll(launchSeveralRuns(parseInt(USER_MAX_RUNS))); + launchToolWithError(USER_MAX_RUNS, format(warningMessage, USER_MAX_RUNS), + format(launchErrorMessage, user.login, USER_LIMIT, USER_MAX_RUNS)); + runsMenu() + .viewAvailableActiveRuns() + .resume(runID3[0], nameWithoutGroup(tool)) + .messageShouldAppear(format(launchErrorMessage, user.login, USER_LIMIT, USER_MAX_RUNS)) + .completedRuns() + .rerun(runID3[1]) + .expandTab(EXEC_ENVIRONMENT) + .ensure(byText(format(warningMessage, USER_MAX_RUNS)), visible) + .checkLaunchMessage("message", + format(warningMessage, USER_MAX_RUNS), true) + .launchWithError(format(launchErrorMessage, user.login, USER_LIMIT, USER_MAX_RUNS)); + runsMenu() + .showLog(runIDs.get(0)) + .waitForSshLink() + .ssh(shell -> shell + .waitUntilTextAppears(runIDs.get(0)) + .execute(runToolCommand) + .assertPageAfterCommandContainsStrings(runToolCommand, + format(launchErrorMessage, user.login, USER_LIMIT, USER_MAX_RUNS)) + .execute("pipe users instances --verbose") + .assertPageContainsString("The following restrictions applied on runs launching:") + .assertPageContains(USER_GROUP, GROUP_MAX_RUNS2) + .assertPageContains(USER_GROUP2, GROUP_MAX_RUNS1) + .assertPageContains(GLOBAL_LIMIT, GLOBAL_MAX_RUNS) + .assertPageContains(USER_LIMIT, USER_MAX_RUNS) + .close()); + } finally { + refreshPage(); + final RunsMenuAO runsMenuAO = runsMenu(); + if (runsMenuAO.isActiveRun(runID3[0])) { + runsMenuAO + .terminateRun(runID3[0], format("pipeline-%s", runID3[0])); + } + runIDs.forEach(runID -> runsMenuAO.viewAvailableActiveRuns().stopRun(runID)); + } + } + + @Test(priority = 2) + @TestCase(value = {"2642_5"}) + public void checkRunningInstancesRestrictionForClusterRun() { + setUserAllowedInstanceMaxCount(user, USER_MAX_RUNS); + logout(); + loginAs(user); + runID5.addAll(launchSeveralRuns(1)); + tools() + .perform(registry, group, tool, ToolTab::runWithCustomSettings) + .enableClusterLaunch() + .clusterSettingsForm("Cluster") + .setWorkingNodesCount("2") + .checkWarningMessageExist(format(warningMessage, USER_MAX_RUNS)) + .ok() + .doNotMountStoragesSelect(true) + .ensure(byText(format(warningMessage, USER_MAX_RUNS)), visible) + .checkLaunchMessage("message", + format(warningMessage, USER_MAX_RUNS), true) + .launchWithError(format(launchErrorMessage, user.login, USER_LIMIT, USER_MAX_RUNS)); + tools() + .perform(registry, group, tool, ToolTab::runWithCustomSettings) + .enableClusterLaunch() + .clusterSettingsForm("Cluster") + .setWorkingNodesCount("1") + .checkWarningMessageNotExist() + .ok() + .doNotMountStoragesSelect(true) + .launch(this); + runID5.add(getLastRunId()); + runsMenu() + .showLog(runID5.get(0)) + .waitForSshLink() + .ssh(shell -> shell + .waitUntilTextAppears(runID5.get(0)) + .execute("pipe users instances") + .assertPageContains( + format("Active runs detected for a user: [%s: %s]", user.login, USER_MAX_RUNS)) + .close()); + } + + @Test(priority = 2, dependsOnMethods = "checkRunningInstancesRestrictionForClusterRun") + @TestCase(value = {"2642_6"}) + public void checkRunningInstancesRestrictionForLaunchToolWithConfiguredClusterRun() { + try { + tools() + .performWithin(registry, group, tool, tool -> + tool.settings() + .enableClusterLaunch() + .clusterSettingsForm("Cluster") + .setWorkingNodesCount("2") + .ok() + .performIf(SAVE, enabled, ToolSettings::save) + ); + logout(); + loginAs(user); + launchToolWithError(USER_MAX_RUNS, format(warningMessage, USER_MAX_RUNS), + format(launchErrorMessage, user.login, USER_LIMIT, USER_MAX_RUNS)); + } finally { + refreshPage(); + tools() + .performWithin(registry, group, tool, tool -> + tool.settings() + .enableClusterLaunch() + .clusterSettingsForm("Single node") + .ok() + .performIf(SAVE, enabled, ToolSettings::save) + ); + runID5.forEach(runID -> runsMenu().viewAvailableActiveRuns().stopRun(runID)); + } + } + + @Test(priority = 3) + @TestCase(value = {"2642_7"}) + public void checkRunningInstancesRestrictionForAutoScaledClusterRun() { + setUserAllowedInstanceMaxCount(user, USER_MAX_RUNS); + logout(); + loginAs(user); + launchSeveralRuns(1); + tools() + .perform(registry, group, tool, ToolTab::runWithCustomSettings) + .enableClusterLaunch() + .clusterSettingsForm("Auto-scaled cluster") + .setWorkingNodesCount("3") + .checkWarningMessageExist(format(autoScaledClusterWarning, "is 1 job", USER_MAX_RUNS)) + .setDefaultChildNodes("2") + .checkWarningMessageExist(format(warningMessage, USER_MAX_RUNS)) + .setDefaultChildNodes("1") + .checkWarningMessageExist(format(autoScaledClusterWarning, "is 1 job", USER_MAX_RUNS)) + .ok() + .doNotMountStoragesSelect(true) + .ensure(byText(format(autoScaledClusterWarning, "is 1 job", USER_MAX_RUNS)), visible) + .checkLaunchMessage("message", + format(autoScaledClusterWarning, "is 1 job", USER_MAX_RUNS), true) + .launch(this) + .shouldContainRun("pipeline", getLastRunId()) + .openClusterRuns(getLastRunId()) + .shouldContainRunsWithParentRun(1, getLastRunId()) + .showLog(getLastRunId()) + .waitForSshLink() + .ssh(shell -> shell + .waitUntilTextAppears(getLastRunId()) + .execute("pipe users instances") + .assertPageContains( + format("Active runs detected for a user: [%s: %s]", user.login, USER_MAX_RUNS)) + .close()); + } + + private List launchSeveralRuns(int count) { + final List runIDs = new ArrayList<>(); + IntStream.range(0, count) + .forEach(i -> { + tools().perform(registry, group, tool, tool -> + tool.run(this)); + runIDs.add(getLastRunId()); + }); + return runIDs; + } + + private void launchToolWithError(String count, String formMessage, String launchMessage) { + tools() + .perform(registry, group, tool, ToolTab::runWithCustomSettings) + .expandTab(EXEC_ENVIRONMENT) + .ensure(byText(format(formMessage, count)), visible) + .checkLaunchMessage("message", format(formMessage, count), true) + .launchWithError(launchMessage); + } + + private void setGroupAllowedInstanceMaxCount(String group, String value) { + navigationMenu() + .settings() + .switchToUserManagement() + .switchToGroups() + .editGroup(group) + .ensure(byText(ALLOWED_INSTANCES_MAX_COUNT), visible, enabled) + .addAllowedInstanceMaxCount(value) + .ok(); + } + + private void setUserAllowedInstanceMaxCount(Account userName, String value) { + navigationMenu() + .settings() + .switchToUserManagement() + .switchToUsers() + .searchUserEntry(userName.login) + .edit() + .ensure(byText(ALLOWED_INSTANCES_MAX_COUNT), visible, enabled) + .addAllowedInstanceMaxCount(value) + .ok(); + } +} diff --git a/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/PipelineRunFormAO.java b/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/PipelineRunFormAO.java index ce8e086159..ae278d90ec 100644 --- a/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/PipelineRunFormAO.java +++ b/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/PipelineRunFormAO.java @@ -34,6 +34,7 @@ import static com.codeborne.selenide.Condition.*; import static com.codeborne.selenide.Selectors.*; +import static com.codeborne.selenide.Selectors.byClassName; import static com.codeborne.selenide.Selenide.*; import static com.epam.pipeline.autotests.ao.Primitive.*; import static com.epam.pipeline.autotests.utils.PipelineSelectors.button; @@ -45,6 +46,7 @@ import static org.openqa.selenium.By.tagName; import org.openqa.selenium.NoSuchWindowException; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; import static org.testng.Assert.fail; public class PipelineRunFormAO implements AccessObject { @@ -62,7 +64,7 @@ public class PipelineRunFormAO implements AccessObject { entry(DISK, context().find(byId("exec.disk"))), entry(TIMEOUT, context().find(byId("advanced.timeout"))), entry(CONFIGURATION, context().find(byXpath("//*[.//*[contains(text(), 'Configuration name')] and contains(@class, 'ant-select-selection')]"))), - entry(LAUNCH_CLUSTER, context().find(byText("Configure cluster"))), + entry(LAUNCH_CLUSTER, context().find(byClassName("underline"))), entry(START_IDLE, context().find(byText("Start idle")).closest(".ant-checkbox-wrapper")), entry(EXEC_ENVIRONMENT, context().find(byId("launch-pipeline-exec-environment-panel"))), entry(ADVANCED_PANEL, context().find(byId("launch-pipeline-advanced-panel"))), @@ -203,7 +205,7 @@ public PipelineRunFormAO checkTooltipText(String capability, String tooltip) { return this; } - public ConfigureClusterPopupAO enableClusterLaunch() { + public ConfigureClusterPopupAO enableClusterLaunch() { click(LAUNCH_CLUSTER); return new ConfigureClusterPopupAO(this); } @@ -304,7 +306,7 @@ private boolean checkMessage(final String typeMessage, final String message) { .findBy(text("Launch")) .find(byClassName("ob-estimated-price-info__info")) .shouldBe(visible); - boolean messageExist = context().$(byClassName("ant-modal-body")) + boolean messageExist = context().$(byClassName("ant-confirm-content")) .findAll(byClassName(format("ant-alert-%s", typeMessage))) .stream() .map(SelenideElement::getText) @@ -337,6 +339,12 @@ public PipelineRunFormAO launch() { return this; } + public PipelineRunFormAO launchWithError(String errorMessage) { + launch(); + messageShouldAppear(errorMessage); + return this; + } + public PipelineRunFormAO validateThereIsParameterOfType(String name, String value, ParameterType type, boolean required) { final String parameterNameClass = "launch-pipeline-form__parameter-name"; final SelenideElement nameElement = $(byXpath(format( @@ -411,7 +419,7 @@ public PipelineRunFormAO chooseConfiguration(final String profileName) { } public PipelineRunFormAO checkConfigureClusterLabel(String label) { - context().find(byXpath(".//div[@class='ant-row-flex launch-pipeline-form__form-item-container']/a")) + context().find(byClassName("underline")) .shouldBe(visible).shouldHave(text(label)); return this; } @@ -575,16 +583,17 @@ public SystemParameterPopupAO validateNotFoundParameters() { } } - public static class ConfigureClusterPopupAO extends PopupAO { + public static class ConfigureClusterPopupAO extends PopupAO, PARENT_AO> { private final Map elements = initialiseElements( - entry(WORKERS_PRICE_TYPE, context().find(byText("Workers price type:")).parent().find(byClassName("ant-select-selection--single"))), + entry(WORKERS_PRICE_TYPE, context().find(byText("Workers price type:")) + .parent().find(byClassName("ant-select-selection--single"))), entry(WORKING_NODES, context().find(byXpath("(.//*[@class = 'ant-input-number-input'])[1]"))), entry(DEFAULT_CHILD_NODES, context().find(byXpath("(.//*[@class = 'ant-input-number-input'])[last()]"))), entry(RESET, context().$(byXpath("//*[contains(text(), 'Reset')]"))) ); - public ConfigureClusterPopupAO(PipelineRunFormAO parentAO) { + public ConfigureClusterPopupAO(PARENT_AO parentAO) { super(parentAO); } @@ -593,7 +602,7 @@ public Map elements() { return elements; } - public ConfigureClusterPopupAO clusterSettingsForm(String type){ + public ConfigureClusterPopupAO clusterSettingsForm(String type){ if (type.equals("Single node") || type.equals("Cluster") || type.equals("Auto-scaled cluster")) { context() .find(byXpath( @@ -605,20 +614,23 @@ public ConfigureClusterPopupAO clusterSettingsForm(String type){ return this; } - public ConfigureClusterPopupAO setWorkingNodesCount(final String nodesCount) { + public ConfigureClusterPopupAO setWorkingNodesCount(final String nodesCount) { return setValue(WORKING_NODES, nodesCount); } - public ConfigureClusterPopupAO setDefaultChildNodes(final String nodesCount) { - $(byText("Setup default child nodes count")).click(); + public ConfigureClusterPopupAO setDefaultChildNodes(final String nodesCount) { + final SelenideElement setupDefault = $(byText("Setup default child nodes count")); + if(setupDefault.exists()) { + setupDefault.click(); + } return setValue(DEFAULT_CHILD_NODES, nodesCount); } - public ConfigureClusterPopupAO resetClusterChildNodes () { + public ConfigureClusterPopupAO resetClusterChildNodes () { return click(RESET); } - public ConfigureClusterPopupAO setWorkersPriceType(final String priceType) { + public ConfigureClusterPopupAO setWorkersPriceType(final String priceType) { click(WORKERS_PRICE_TYPE); context().find(visible(byClassName("ant-select-dropdown"))).find(byText(priceType)) .shouldBe(visible) @@ -626,12 +638,12 @@ public ConfigureClusterPopupAO setWorkersPriceType(final String priceType) { return this; } - public ConfigureClusterPopupAO enableHybridClusterSelect () { + public ConfigureClusterPopupAO enableHybridClusterSelect () { $(byXpath(".//span[.='Enable Hybrid cluster']/preceding-sibling::span")).click(); return this; } - public ConfigureClusterPopupAO clusterEnableCheckboxSelect(String checkBox){ + public ConfigureClusterPopupAO clusterEnableCheckboxSelect(String checkBox){ if (checkBox.equals("Enable GridEngine") || checkBox.equals("Enable Apache Spark") || checkBox.equals("Enable Slurm") @@ -645,5 +657,20 @@ public ConfigureClusterPopupAO clusterEnableCheckboxSelect(String checkBox){ } return this; } + + public ConfigureClusterPopupAO checkWarningMessageExist(final String message) { + sleep(5, SECONDS); + assertEquals(message, + $(byClassName("ant-modal-content")).find(byClassName("ant-alert-message")).text(), + format("Message '%s' isn't visible", message)); + return this; + } + + public ConfigureClusterPopupAO checkWarningMessageNotExist() { + sleep(5, SECONDS); + assertFalse($(byClassName("ant-modal-content")).find(byClassName("ant-alert-message")).exists(), + "Warning message shouldn't be visible"); + return this; + } } } diff --git a/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/RunsMenuAO.java b/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/RunsMenuAO.java index a0aff53c8f..04e5ef4e69 100644 --- a/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/RunsMenuAO.java +++ b/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/RunsMenuAO.java @@ -395,6 +395,11 @@ public RunsMenuAO resume(final String runId, final String pipelineName) { return this; } + public PipelineRunFormAO rerun(final String runId) { + $("#run-" + runId + "-rerun-button").shouldBe(visible).click(); + return new PipelineRunFormAO(); + } + public RunsMenuAO waitUntilStopButtonAppear(final String runId) { $("#run-" + runId + "-stop-button").waitUntil(appear, APPEARING_TIMEOUT); return this; diff --git a/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/SettingsPageAO.java b/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/SettingsPageAO.java index f967c69a4b..08ed8afd14 100644 --- a/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/SettingsPageAO.java +++ b/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/SettingsPageAO.java @@ -29,6 +29,7 @@ import org.openqa.selenium.Keys; import org.openqa.selenium.SearchContext; import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; import java.awt.*; import java.awt.datatransfer.StringSelection; @@ -841,6 +842,16 @@ public UsersTabAO deleteUser(final String user) { public EditUserPopup addAllowedLaunchOptions(final String option, final String mask) { SettingsPageAO.this.addAllowedLaunchOptions(option, mask); + sleep(1, SECONDS); + return this; + } + + public EditUserPopup addAllowedInstanceMaxCount(final String value) { + if (StringUtils.isBlank(value)) { + clearByKey(byClassName("ant-input-number-input")); + return this; + } + setValue(byClassName("ant-input-number-input"), value); return this; } @@ -954,6 +965,13 @@ public CreateGroupPopup pressCreateGroup() { return new CreateGroupPopup(this); } + public GroupsTabAO createGroupIfNoPresent(final String group) { + searchGroupBySubstring(group.split(StringUtils.SPACE)[0]); + performIf(!context().$$(byText(group)).filterBy(visible).first().exists(), t -> + pressCreateGroup().enterGroupName(group).create()); + return this; + } + public GroupsTabAO deleteGroupIfPresent(String group) { sleep(2, SECONDS); searchGroupBySubstring(group.split(StringUtils.SPACE)[0]); @@ -1044,7 +1062,9 @@ public class EditGroupPopup extends PopupAO public final Map elements = initialiseElements( entry(OK, context().find(By.id("close-edit-user-form"))), entry(PRICE_TYPE, context().find(byXpath( - format("//div/b[text()='%s']/following::div/input", "Allowed price types")))) + format("//div/b[text()='%s']/following::div/input", "Allowed price types")))), + entry(SEARCH, $(By.id("find-user-autocomplete-container"))), + entry(ADD, context().find(By.id("add-user-button"))) ); public EditGroupPopup(final GroupsTabAO parentAO) { @@ -1063,8 +1083,28 @@ public GroupsTabAO ok() { return parentAO; } + public EditGroupPopup addUser(final Account name) { + click(SEARCH); + actions().sendKeys(name.login).perform(); + $(byClassName("ant-select-dropdown")).shouldBe(Condition.visible); + enter(); + click(ADD); + return this; + } + public EditGroupPopup addAllowedLaunchOptions(String option, String mask) { SettingsPageAO.this.addAllowedLaunchOptions(option, mask); + sleep(1, SECONDS); + return this; + } + + public EditGroupPopup addAllowedInstanceMaxCount(final String value) { + final By optionField = byClassName("ant-input-number-input"); + if (StringUtils.isBlank(value)) { + clearByKey(optionField); + return this; + } + setValue(optionField, value); return this; } @@ -1243,6 +1283,16 @@ public PreferencesAO setPreference(String preference, String value, boolean eyeI return this; } + public PreferencesAO setNumberPreference(final String preference, + final String value, + final boolean eyeIsChecked) { + searchPreference(preference); + final Actions action = actions().moveToElement($(byClassName("CodeMirror-line"))).click(); + action.sendKeys(Keys.chord(Keys.CONTROL, "a")).sendKeys(value).perform(); + setEyeOption(eyeIsChecked); + return this; + } + public String[] getPreference(String preference) { searchPreference(preference); $(byClassName("CodeMirror-code")).shouldBe(visible); @@ -1837,8 +1887,10 @@ private void addAllowedLaunchOptions(final String option, final String mask) { final By optionField = byXpath(format("//div/b[text()='%s']/following::div/input", option)); if (StringUtils.isBlank(mask)) { clearByKey(optionField); + sleep(3, SECONDS); return; } setValue(optionField, mask); + sleep(3, SECONDS); } } diff --git a/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/ShellAO.java b/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/ShellAO.java index cbe7a38f21..37b37a9065 100644 --- a/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/ShellAO.java +++ b/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/ShellAO.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2022 EPAM Systems, Inc. (https://www.epam.com/) + * Copyright 2017-2023 EPAM Systems, Inc. (https://www.epam.com/) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -98,6 +98,8 @@ public ShellAO assertOutputDoesNotContain(String... messages) { } public ShellAO assertPageAfterCommandContainsStrings(String command, String... messages) { + sleep(2, SECONDS); + screenshot("check_command_out_" + Utils.randomSuffix()); Arrays.stream(messages) .forEach(message -> assertTrue(lastCommandResult(command).contains(message))); return this; diff --git a/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/ToolSettings.java b/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/ToolSettings.java index 52d74f3623..0b875be281 100644 --- a/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/ToolSettings.java +++ b/e2e/gui/src/test/java/com/epam/pipeline/autotests/ao/ToolSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2022 EPAM Systems, Inc. (https://www.epam.com/) + * Copyright 2017-2023 EPAM Systems, Inc. (https://www.epam.com/) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; -import com.epam.pipeline.autotests.utils.PipelineSelectors; import com.epam.pipeline.autotests.utils.Utils; import java.util.Arrays; import java.util.List; @@ -31,18 +30,17 @@ import static com.codeborne.selenide.Condition.enabled; import static com.codeborne.selenide.Condition.exist; import static com.codeborne.selenide.Condition.visible; -import static com.codeborne.selenide.Selectors.by; import static com.codeborne.selenide.Selectors.byAttribute; import static com.codeborne.selenide.Selectors.byClassName; import static com.codeborne.selenide.Selectors.byCssSelector; import static com.codeborne.selenide.Selectors.byId; import static com.codeborne.selenide.Selectors.byText; -import static com.codeborne.selenide.Selectors.byTitle; import static com.codeborne.selenide.Selectors.byValue; import static com.codeborne.selenide.Selectors.byXpath; import static com.codeborne.selenide.Selectors.withText; import static com.codeborne.selenide.Selenide.$; import static com.epam.pipeline.autotests.ao.Primitive.*; +import static com.epam.pipeline.autotests.ao.PipelineRunFormAO.ConfigureClusterPopupAO; import static com.epam.pipeline.autotests.utils.PipelineSelectors.button; import static com.epam.pipeline.autotests.utils.PipelineSelectors.visible; import static java.util.concurrent.TimeUnit.SECONDS; @@ -82,7 +80,8 @@ public ToolSettings(final ToolGroup toolGroup, final String toolName) { entry(ADD_SYSTEM_PARAMETER, context().find(button("Add system parameters"))), entry(ADD_PARAMETER, context().find(byId("add-parameter-button"))), entry(RUN_CAPABILITIES, context().find(byXpath("//*[contains(text(), 'Run capabilities')]")) - .closest(".ant-row").find(className("ant-form-item-control "))) + .closest(".ant-row").find(className("ant-form-item-control "))), + entry(LAUNCH_CLUSTER, context().find(byClassName("underline"))) ); } @@ -298,4 +297,9 @@ public ToolSettings checkCapabilityTooltip(final String capability, final String .shouldHave(Condition.text(text)); return this; } + + public ConfigureClusterPopupAO enableClusterLaunch() { + click(LAUNCH_CLUSTER); + return new ConfigureClusterPopupAO<>(this); + } } diff --git a/e2e/gui/testng.xml b/e2e/gui/testng.xml index b8db124899..61d002ded7 100644 --- a/e2e/gui/testng.xml +++ b/e2e/gui/testng.xml @@ -526,6 +526,12 @@ + + + + + +