JENKINS-43906: Git creation ath tests (#1217)

* Test

* Update jenkinsfile'

* typo

* typo

* Increase timeout

* more timeouts

* Refresh page

* wayward backtick

One day we will crash into mars because of a typo

* adding in a reload for activity screen

* relaxing timeouts

* Use sse for refresh

* debugging

* reorder tests

* hail mary

* More debugging

* Ignore test
This commit is contained in:
Ivan Meredith 2017-07-17 16:22:42 +12:00 committed by GitHub
parent 40ed3e647e
commit 5af7343343
11 changed files with 245 additions and 10 deletions

3
Jenkinsfile vendored
View File

@ -14,6 +14,9 @@ node() {
configFileProvider([configFile(fileId: 'blueocean-maven-settings', variable: 'MAVEN_SETTINGS')]) {
sh 'mv $MAVEN_SETTINGS settings.xml'
}
withCredentials([file(credentialsId: 'blueocean-ath-private-repo-key', variable: 'FILE')]) {
sh 'mv $FILE acceptance-tests/bo-ath.key'
}
sh "./acceptance-tests/runner/scripts/start-selenium.sh"
}

View File

@ -0,0 +1,21 @@
github.repo=
github.org=
github.token=
github.deleteRepo=true
github.randomSuffix=true
# git@github.com:myorg/private-repo.git
git.ssh.repository=
# /Users/ivan/.ssh/id_rsa
git.ssh.keyfile=
# Name of the created pipeline (will match repo name).
git.ssh.pipelineName=
# https://github.com/myorg/private-repo.git
git.https.repository=
# org/user
git.https.user=
# personal access token
git.https.pass=
# Name of the created pipeline (will match repo name).
git.https.pipelineName=

View File

@ -82,7 +82,7 @@ public class ATHJUnitRunner extends BlockJUnit4ClassRunner {
WebDriver driver = injector.getInstance(WebDriver.class);
driver.close();
driver.quit();
// driver.quit();
}
};
}

View File

@ -2,6 +2,7 @@ package io.blueocean.ath;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.name.Names;
import com.offbytwo.jenkins.JenkinsServer;
import io.blueocean.ath.factory.ActivityPageFactory;
import io.blueocean.ath.factory.BranchPageFactory;
@ -18,10 +19,14 @@ import org.openqa.selenium.remote.Augmenter;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Properties;
public class AthModule extends AbstractModule {
@Override
@ -47,12 +52,15 @@ public class AthModule extends AbstractModule {
"jenkins.model.Jenkins.getInstance().setNumExecutors(10);\n" +
"jenkins.model.Jenkins.getInstance().save();\n");
}
Properties properties = new Properties();
properties.load(new FileInputStream("live.properties"));
bind(Properties.class).annotatedWith(Names.named("live")).toInstance(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
install(new FactoryModuleBuilder()
.implement(ActivityPage.class, ActivityPage.class)
.build(ActivityPageFactory.class));

View File

@ -17,6 +17,7 @@ import org.openqa.selenium.support.ui.ExpectedConditions;
import javax.inject.Inject;
import java.net.URLEncoder;
import java.util.List;
public class ActivityPage {
private Logger logger = Logger.getLogger(ActivityPage.class);
@ -58,13 +59,13 @@ public class ActivityPage {
public ActivityPage checkUrl() {
wait.until(ExpectedConditions.urlContains(pipeline.getUrl() + "/activity"), 120000);
wait.until(By.cssSelector("article.activity"));
wait.until(By.cssSelector("article.activity"), 60000);
return this;
}
public ActivityPage checkUrl(String filter) {
wait.until(ExpectedConditions.urlContains(pipeline.getUrl() + "/activity?branch=" + URLEncoder.encode(URLEncoder.encode(filter))), 30000);
wait.until(By.cssSelector("article.activity"));
wait.until(By.cssSelector("article.activity"), 60000);
return this;
}
@ -103,4 +104,10 @@ public class ActivityPage {
final String durationRegex = "<1s|\\d+\\w";
Assert.assertTrue("String (\"" + text + "\") contains a valid duration", text.matches(durationRegex));
}
public void testNumberRunsComplete(int atLeast) {
By selector = By.cssSelector("div[data-pipeline='" + pipeline.getName() + "'].JTable-row circle.success");
wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(selector, atLeast - 1));
logger.info("At least " + atLeast + " runs are complete");
}
}

View File

@ -116,4 +116,11 @@ public class DashboardPage {
public void clickPipeline(String pipelineName){
wait.until(By.xpath("//*/div[@data-pipeline='" + pipelineName + "']/a[1]")).click();
}
public void clickNewPipelineBtn() {
open();
wait.until(newPipelineButton).click();
wait.until(ExpectedConditions.urlContains("create-pipeline"));
logger.info("Clicked new pipeline");
}
}

View File

@ -0,0 +1,84 @@
package io.blueocean.ath.pages.blue;
import com.google.common.base.Strings;
import io.blueocean.ath.WaitUtil;
import io.blueocean.ath.api.classic.ClassicJobApi;
import io.blueocean.ath.factory.MultiBranchPipelineFactory;
import io.blueocean.ath.factory.PipelineFactory;
import io.blueocean.ath.model.MultiBranchPipeline;
import io.blueocean.ath.model.Pipeline;
import io.blueocean.ath.sse.SSEClientRule;
import io.blueocean.ath.sse.SSEEvents;
import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
@Singleton
public class GitCreationPage {
private Logger logger = Logger.getLogger(GitCreationPage.class);
private WebDriver driver;
@Inject
WaitUtil wait;
@Inject
DashboardPage dashboardPage;
@Inject
ClassicJobApi jobApi;
@Inject
MultiBranchPipelineFactory multiBranchPipelineFactory;
@Inject
public GitCreationPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public GitCreationPage clickGitCreationOption() {
wait.until(By.xpath("//span[text()='Git']")).click();
logger.info("Selected git creation");
return this;
}
public MultiBranchPipeline createPipeline(SSEClientRule sseCLient, String pipelineName, String url, String sshPrivateKey, String user, String pass) throws IOException {
jobApi.deletePipeline(pipelineName);
dashboardPage.clickNewPipelineBtn();
clickGitCreationOption();
wait.until(By.cssSelector("div.text-repository-url input")).sendKeys(url);
wait.until(By.cssSelector("button.button-create-credential")).click();
if(!Strings.isNullOrEmpty(sshPrivateKey)) {
wait.until(By.xpath("//span[text()='SSH Key']")).click();
wait.until(By.cssSelector("textarea.TextArea-control")).sendKeys(sshPrivateKey);
wait.until(By.cssSelector(".Dialog-button-bar button.button-create-credental")).click();
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector(".create-credential-dialog")));
logger.info("Created credential");
} else if(!Strings.isNullOrEmpty(user) && !Strings.isNullOrEmpty(pass)) {
wait.until(By.xpath("//span[text()='Username & Password']")).click();
wait.until(By.cssSelector("div.text-username input")).sendKeys(user);
wait.until(By.cssSelector("div.text-password input")).sendKeys(pass);
wait.until(By.cssSelector(".Dialog-button-bar button.button-create-credental")).click();
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector(".create-credential-dialog")));
logger.info("Created user/pass credential");
}
wait.until(By.cssSelector(".button-create-pipeline")).click();
logger.info("Click create pipeline button");
MultiBranchPipeline pipeline = multiBranchPipelineFactory.pipeline(pipelineName);
wait.until(ExpectedConditions.urlContains(pipeline.getUrl() + "/activity"), 30000);
sseCLient.untilEvents(SSEEvents.activityComplete(pipeline.getName()));
driver.navigate().refresh();
pipeline.getActivityPage().checkUrl();
return pipeline;
}
}

View File

@ -9,6 +9,7 @@ import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -52,12 +53,18 @@ public class LoginPage{
open();
wait.until(loginUsername).sendKeys(getUsername());
WebElement usernameField = wait.until(By.id("j_username"));
usernameField.sendKeys(getUsername());
wait.until(loginPassword).sendKeys(getPassword());
wait.until(By.name("j_password")).sendKeys(getPassword());
wait.until(By.xpath("//*/button[contains(text(), 'log')]")).click();
wait.until(driver -> {
if(driver.getCurrentUrl().contains("loginError")) {
throw new RuntimeException("Error logging in");
}
return ExpectedConditions.urlToBe(base + "/").apply(driver);
});
logger.info("Logged in as alice");
}
}

View File

@ -74,7 +74,16 @@ public class SSEClientRule extends ExternalResource {
private EventListener listener = inboundEvent -> {
JSONObject jenkinsEvent = new JSONObject(inboundEvent.readData());
events.add(jenkinsEvent);
if(jenkinsEvent.has("jenkins_event") && jenkinsEvent.getString("jenkins_event").equals("job_run_queue_enter")) {
if(jenkinsEvent.has("jenkins_object_type") &&
jenkinsEvent.getString("jenkins_object_type").equals("org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject")) {
} else
if(jenkinsEvent.has("blueocean_job_pipeline_name")) {
String pipelineName = jenkinsEvent.getString("blueocean_job_pipeline_name");
logger.info("Build for " + pipelineName + " entered queue");
}
}
events.add(jenkinsEvent);
if(logEvents) {
logger.info("SSE - " + jenkinsEvent.toString());
}

View File

@ -25,8 +25,11 @@ public class SSEEvents {
json.getString("jenkins_object_type").equals("org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject")) {
continue;
}
if(json.has("blueocean_job_pipeline_name") && json.getString("blueocean_job_pipeline_name").equals(jobName)) {
jobsQueued.add(json);
if(json.has("blueocean_job_pipeline_name")) {
String pipelineName = json.getString("blueocean_job_pipeline_name");
if (pipelineName.equals(jobName)) {
jobsQueued.add(json);
}
}
}
if(json.has("jenkins_event") && json.getString("jenkins_event").equals("job_run_ended")) {

View File

@ -0,0 +1,86 @@
package io.blueocean.ath.live.creation;
import io.blueocean.ath.ATHJUnitRunner;
import io.blueocean.ath.BaseTest;
import io.blueocean.ath.GitRepositoryRule;
import io.blueocean.ath.Login;
import io.blueocean.ath.WaitUtil;
import io.blueocean.ath.model.MultiBranchPipeline;
import io.blueocean.ath.model.Pipeline;
import io.blueocean.ath.pages.blue.DashboardPage;
import io.blueocean.ath.pages.blue.GitCreationPage;
import io.blueocean.ath.sse.SSEClientRule;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.support.ui.ExpectedConditions;
import javax.inject.Inject;
import javax.inject.Named;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Properties;
@Login
@RunWith(ATHJUnitRunner.class)
public class GitCreationTest extends BaseTest{
private Logger logger = Logger.getLogger(GitCreationTest.class);
@Inject @Named("live")
Properties liveProperties;
@Inject
DashboardPage dashboardPage;
@Inject
GitCreationPage gitCreationPage;
@Inject
WaitUtil wait;
@Inject @Rule
public SSEClientRule sseClient;
@Test
public void testHttpsPrivateRepository() throws IOException, GitAPIException, URISyntaxException {
String gitUrl = liveProperties.getProperty("git.https.repository");
String user = liveProperties.getProperty("git.https.user");
String pass = liveProperties.getProperty("git.https.pass");
String pipelineName = liveProperties.getProperty("git.https.pipelineName");
Assert.assertNotNull(gitUrl);
Assert.assertNotNull(user);
Assert.assertNotNull(pass);
Assert.assertNotNull(pipelineName);
logger.info("PipelineNameHttps: " + pipelineName);
logger.info("git repo - " + gitUrl);
Pipeline pipeline = gitCreationPage.createPipeline(sseClient, pipelineName, gitUrl, null, user, pass);
pipeline.getActivityPage().testNumberRunsComplete(1);
}
@Ignore
@Test
public void testSSHPrivateRepostory() throws IOException, GitAPIException, URISyntaxException {
String gitUrl = liveProperties.getProperty("git.ssh.repository");
String privateKeyFile = liveProperties.getProperty("git.ssh.keyfile");
String pipelineName = liveProperties.getProperty("git.ssh.pipelineName");
Assert.assertNotNull(gitUrl);
Assert.assertNotNull(privateKeyFile);
Assert.assertNotNull(pipelineName);
logger.info("PipelineName: " + pipelineName);
logger.info("git repo - " + gitUrl);
String key = IOUtils.toString(new FileInputStream(privateKeyFile));
MultiBranchPipeline pipeline = gitCreationPage.createPipeline(sseClient, pipelineName, gitUrl, key, null, null);
pipeline.getActivityPage().testNumberRunsComplete(1);
}
}