diff --git a/app/cdap/components/SourceControlManagement/LocalPipelineListView/PipelineTable.tsx b/app/cdap/components/SourceControlManagement/LocalPipelineListView/PipelineTable.tsx index 8eabac2dc49..0284d185ca3 100644 --- a/app/cdap/components/SourceControlManagement/LocalPipelineListView/PipelineTable.tsx +++ b/app/cdap/components/SourceControlManagement/LocalPipelineListView/PipelineTable.tsx @@ -99,7 +99,7 @@ export const LocalPipelineTable = ({ return ( - +
diff --git a/app/cdap/components/SourceControlManagement/LocalPipelineListView/index.tsx b/app/cdap/components/SourceControlManagement/LocalPipelineListView/index.tsx index d9f7cfa8295..5b57b300607 100644 --- a/app/cdap/components/SourceControlManagement/LocalPipelineListView/index.tsx +++ b/app/cdap/components/SourceControlManagement/LocalPipelineListView/index.tsx @@ -213,6 +213,7 @@ export const LocalPipelineListView = () => { variant="filled" severity={getOperationStatusType(operation)} action={getOperationAction()} + data-testid="latest_operation_banner" > {getOperationRunMessage(operation)} {getOperationStartTime(operation)} diff --git a/app/cdap/components/SourceControlManagement/RemotePipelineListView/index.tsx b/app/cdap/components/SourceControlManagement/RemotePipelineListView/index.tsx index 6456012b655..c2b9684e686 100644 --- a/app/cdap/components/SourceControlManagement/RemotePipelineListView/index.tsx +++ b/app/cdap/components/SourceControlManagement/RemotePipelineListView/index.tsx @@ -233,6 +233,7 @@ export const RemotePipelineListView = ({ redirectOnSubmit }: IRemotePipelineList variant="filled" severity={getOperationStatusType(operation)} action={getOperationAction()} + data-testid="latest_operation_banner" > {getOperationRunMessage(operation)} {getOperationStartTime(operation)} diff --git a/server/config/development/cdap.json b/server/config/development/cdap.json index a8fd10b4487..2c00d40371d 100644 --- a/server/config/development/cdap.json +++ b/server/config/development/cdap.json @@ -15,6 +15,8 @@ "ui.theme.file": "config/themes/default.json", "session.secret.key": "sample-secret-key-for-encryption", "feature.lifecycle.management.edit.enabled": "true", + "feature.source.control.management.git.enabled": "true", + "feature.source.control.management.multi.app.enabled": "true", "ui.analyticsTag": "", "ui.GTM": "", "hsts.enabled": "false", diff --git a/src/e2e-test/features/source.control.management.sync.apps.feature b/src/e2e-test/features/source.control.management.sync.apps.feature index ab6a23bc3d1..7bceffbe458 100644 --- a/src/e2e-test/features/source.control.management.sync.apps.feature +++ b/src/e2e-test/features/source.control.management.sync.apps.feature @@ -29,6 +29,74 @@ Feature: Source Control Management - Pulling and pushing applications Then Banner is shown with message "Successfully pushed pipeline test_pipeline2_fll_airport" Then Clean up pipeline "test_pipeline2_fll_airport" which is created for testing + @SOURCE_CONTROL_MANAGEMENT_TEST + Scenario: Should successfully push and pull multiple pipelines to git from sync page + # Setup + When Deploy and test pipeline "test_multi_push_fll_airport" with pipeline JSON file "fll_airport_pipeline2.json" + When Deploy and test pipeline "test_multi_push_logs_generator" with pipeline JSON file "logs_generator.json" + When Deploy and test pipeline "synced_logs_generator" with pipeline JSON file "logs_generator.json" + Then Click push button in Actions dropdown + Then Commit changes with message "upload pipeline to Git" + Then Banner is shown with message "Successfully pushed pipeline synced_logs_generator" + + # Push 2 pipelines in bulk + When Open Source Control Sync Page + When Select local pipeline "test_multi_push_fll_airport" + When Select local pipeline "test_multi_push_logs_generator" + When Push selected pipelines to remote with commit message "upload pipelines to git" + + # Verify that when one operation is running, another operation can not be started + Then Verify "push" operation is running + Then Verify the remote "push" button is disabled + When Select remote pipelines tab + Then Verify "push" operation is running + Then Verify the remote "pull" button is disabled + + # Move to another page and back, the operation should be running + When Open CDAP main page + When Open Source Control Sync Page + Then Verify "push" operation is running + Then Verify the remote "push" button is disabled + + # The push operation should succeed + Then Wait for "push" operation to complete successfully + When Select remote pipelines tab + Then Verify "test_multi_push_fll_airport" pipeline exist in list + Then Verify "test_multi_push_logs_generator" pipeline exist in list + + # Delete these pipelines locally + Then Clean up pipeline "test_multi_push_fll_airport" which is created for testing + Then Clean up pipeline "test_multi_push_logs_generator" which is created for testing + + # Then pull these from remote + When Open Source Control Sync Page + When Select remote pipelines tab + When Select remote pipeline "test_multi_push_fll_airport" + When Select remote pipeline "test_multi_push_logs_generator" + When Pull selected pipelines + + # Verify that when one operation is running, another operation can not be started + Then Verify "pull" operation is running + Then Verify the remote "pull" button is disabled + When Select local pipelines tab + Then Verify "pull" operation is running + Then Verify the remote "push" button is disabled + When Select remote pipelines tab + + # The pull operation should succeed + Then Wait for "pull" operation to complete successfully + When Select local pipelines tab + Then Verify "test_multi_push_fll_airport" pipeline exist in local list + Then Verify "test_multi_push_logs_generator" pipeline exist in local list + When Open pipeline list page + Then Verify pipeline "test_multi_push_fll_airport" is deployed + Then Verify pipeline "test_multi_push_logs_generator" is deployed + + # Cleanup + Then Clean up pipeline "test_multi_push_fll_airport" which is created for testing + And Clean up pipeline "test_multi_push_logs_generator" which is created for testing + And Clean up pipeline "synced_logs_generator" which is created for testing + @SOURCE_CONTROL_MANAGEMENT_TEST Scenario: Remote pipeline tab loads pipelines from git # Setup @@ -37,7 +105,8 @@ Feature: Source Control Management - Pulling and pushing applications When Open Source Control Sync Page When Select "test_pipeline2_fll_airport" pipeline and push Then Commit changes with message "upload pipeline to Git" - Then Push success indicator is shown for pipeline "test_pipeline2_fll_airport" + Then Verify "push" operation is running + Then Wait for "push" operation to complete successfully When Select remote pipelines tab Then Verify pipeline list size 1 Then Verify "test_pipeline2_fll_airport" pipeline exist in list @@ -46,7 +115,12 @@ Feature: Source Control Management - Pulling and pushing applications When Open Source Control Sync Page When Select remote pipelines tab Then Select "test_pipeline2_fll_airport" pipeline and pull - Then Pull success indicator is shown for pipeline "test_pipeline2_fll_airport" + Then Verify "pull" operation is running + Then Wait for "pull" operation to complete successfully + When Select local pipelines tab + Then Verify "test_pipeline2_fll_airport" pipeline exist in local list + When Open pipeline list page + Then Verify pipeline "test_pipeline2_fll_airport" is deployed # Clean up Then Clean up pipeline "test_pipeline2_fll_airport" which is created for testing diff --git a/src/e2e-test/java/io/cdap/cdap/ui/stepsdesign/SourceControlManagement.java b/src/e2e-test/java/io/cdap/cdap/ui/stepsdesign/SourceControlManagement.java index e4df3a5c433..3be17979873 100644 --- a/src/e2e-test/java/io/cdap/cdap/ui/stepsdesign/SourceControlManagement.java +++ b/src/e2e-test/java/io/cdap/cdap/ui/stepsdesign/SourceControlManagement.java @@ -21,6 +21,7 @@ import io.cdap.cdap.ui.utils.Helper; import io.cdap.e2e.utils.ElementHelper; import io.cdap.e2e.utils.PluginPropertyUtils; +import io.cdap.e2e.utils.SeleniumDriver; import io.cdap.e2e.utils.WaitHelper; import io.cucumber.java.en.Then; import io.cucumber.java.en.When; @@ -28,6 +29,7 @@ import org.openqa.selenium.By; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; /** * @@ -207,9 +209,86 @@ public void verifyPipelineList(String pipeline) { ); } + @Then("Verify {string} pipeline exist in local list") + public void verifyLocalPipelineList(String pipeline) { + Assert.assertTrue( + Helper.isElementExists(Helper.getCssSelectorByDataTestId("local-" + pipeline)) + ); + } + + @When("Select local pipeline {string}") + public void selectPipelineFromList(String pipeline) { + ElementHelper.clickOnElement(Helper.locateElementByTestId("local-" + pipeline)); + } + + @When("Select remote pipeline {string}") + public void selectRemotePipelineFromList(String pipeline) { + ElementHelper.clickOnElement(Helper.locateElementByTestId("remote-" + pipeline)); + } + + @When("Push selected pipelines to remote with commit message {string}") + public void pushPipelinesToRemote(String message) { + ElementHelper.clickOnElement(Helper.locateElementByTestId("remote-push-button")); + commitPipeline(message); + } + + @When("Pull selected pipelines") + public void pullSelectedPipelines() { + ElementHelper.clickOnElement(Helper.locateElementByTestId("remote-pull-button")); + } + + @Then("Verify {string} operation is running") + public void verifyOperationIsRunning(String operationType) { + String operationBannerPath = "//*[@data-testid=\"latest_operation_banner\"]"; + WebElement operationBanner = Helper.locateElementByXPath(operationBannerPath); + ElementHelper.isElementDisplayed(operationBanner); + + SeleniumDriver.getWaitDriver(180L).until(ExpectedConditions.or( + ExpectedConditions.textToBePresentInElement(operationBanner, "Pushing"), + ExpectedConditions.textToBePresentInElement(operationBanner, "Pulling") + )); + + String bannerMessage = ElementHelper.getElementText(operationBanner); + String expectedText = operationType.equals("push") ? "Pushing" : "Pulling"; + Assert.assertTrue(bannerMessage.contains(expectedText)); + } + + @Then("Verify the remote {string} button is disabled") + public void verifyRemotePushOrPullButtonIsDisabled(String operationType) { + String buttonXpath = "//*[@data-testid=\"remote-" + operationType + "-button\"]"; + // if the button is not displayed at all, then we do not need to check if it's disabled + if (!ElementHelper.isElementDisplayed(By.xpath(buttonXpath), 1)) { + return; + } + WebElement button = Helper.locateElementByXPath(buttonXpath); + ElementHelper.isElementDisplayed(button); + Assert.assertFalse(button.isEnabled()); + } + + @Then("Wait for {string} operation to complete successfully") + public void waitForOperationToCompleteSuccessfully(String operationType) { + String operationBannerPath = "//*[@data-testid=\"latest_operation_banner\"]"; + WebElement operationBanner = Helper.locateElementByXPath(operationBannerPath); + SeleniumDriver.getWaitDriver(180L).until(ExpectedConditions.or( + ExpectedConditions.textToBePresentInElement(operationBanner, "Successfully"), + ExpectedConditions.textToBePresentInElement(operationBanner, "Failed") + )); + + String bannerMessage = ElementHelper.getElementText(operationBanner); + String expectedText = operationType.equals("push") ? "Successfully pushed" : "Successfully pulled"; + Assert.assertTrue(bannerMessage.contains(expectedText)); + } + + @Then("Verify pipeline {string} is deployed") + public void verifyPipelineIsDeployed(String pipelineName) { + Assert.assertTrue( + Helper.isElementExists(Helper.getCssSelectorByDataTestId("deployed-" + pipelineName)) + ); + } + @When("Select {string} pipeline and push") public void pushPipelineInRemotePage(String pipeline) { - ElementHelper.clickOnElement(Helper.locateElementByTestId("local-" + pipeline)); + selectPipelineFromList(pipeline); ElementHelper.clickOnElement(Helper.locateElementByTestId("remote-push-button")); }