Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ATH IMPROVEMENT] Allow local Jenkins instance, simplified API #1484

Merged
merged 23 commits into from
Oct 23, 2017
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
87ecc77
Update ATH tests for new flow
kzantow Oct 12, 2017
33ccc9c
Handle more close cases for errors
kzantow Oct 12, 2017
f8f224d
Some refactoring
kzantow Oct 12, 2017
f070bbe
Add ability to read a properties file for ATH (~/.blueocean-ath-config)
kzantow Oct 17, 2017
78aa546
Add ability to read a properties file for ATH (~/.blueocean-ath-config)
kzantow Oct 17, 2017
f605005
Add ability to read a properties file for ATH (~/.blueocean-ath-config)
kzantow Oct 17, 2017
8d010e5
Whoops
kzantow Oct 17, 2017
1c58498
Whoops, whoops
kzantow Oct 18, 2017
a17c707
Merge remote-tracking branch 'primary/master' into ATH-allow-local-dev
kzantow Oct 18, 2017
97e6cf4
Whoops, whoops
kzantow Oct 18, 2017
04bb80f
Missed a couple things
kzantow Oct 18, 2017
cdd1ed4
Merge remote-tracking branch 'primary/master' into ATH-allow-local-dev
kzantow Oct 18, 2017
972f4a0
Tweaks based on PR feedback
kzantow Oct 18, 2017
d89172d
Consolidate `go` method
kzantow Oct 18, 2017
2201f7a
Consolidate `go` method
kzantow Oct 18, 2017
5cce6ec
Imports
kzantow Oct 18, 2017
4cb6779
Merge remote-tracking branch 'primary/master' into ATH-allow-local-dev
kzantow Oct 19, 2017
aa434f2
Imports
kzantow Oct 20, 2017
c686b05
Merge remote-tracking branch 'primary/master' into ATH-allow-local-dev
kzantow Oct 21, 2017
fced2e0
Use 'improved' click logic for github pipeline create
kzantow Oct 23, 2017
9922950
Merge remote-tracking branch 'primary/master' into ATH-allow-local-dev
kzantow Oct 23, 2017
add4f4a
Typo
kzantow Oct 23, 2017
dbf0fc2
Merge remote-tracking branch 'primary/master' into ATH-allow-local-dev
kzantow Oct 23, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ private void runTest(Statement statement, Description description,
eachNotifier.addFailure(e);
} finally {
eachNotifier.fireTestFinished();
LocalDriver.destroy();
}
}

Expand Down
57 changes: 49 additions & 8 deletions acceptance-tests/src/main/java/io/blueocean/ath/AthModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@
import com.offbytwo.jenkins.JenkinsServer;
import io.blueocean.ath.factory.ActivityPageFactory;
import io.blueocean.ath.factory.BranchPageFactory;
import io.blueocean.ath.factory.ClassicPipelineFactory;
import io.blueocean.ath.factory.FreestyleJobFactory;
import io.blueocean.ath.factory.MultiBranchPipelineFactory;
import io.blueocean.ath.factory.ClassicPipelineFactory;
import io.blueocean.ath.factory.RunDetailsArtifactsPageFactory;
import io.blueocean.ath.factory.RunDetailsPipelinePageFactory;
import io.blueocean.ath.model.ClassicPipeline;
import io.blueocean.ath.model.FreestyleJob;
import io.blueocean.ath.model.MultiBranchPipeline;
import io.blueocean.ath.model.ClassicPipeline;
import io.blueocean.ath.pages.blue.ActivityPage;
import io.blueocean.ath.pages.blue.BranchPage;
import io.blueocean.ath.pages.blue.RunDetailsArtifactsPage;
import io.blueocean.ath.pages.blue.RunDetailsPipelinePage;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.logging.LoggingPreferences;
Expand All @@ -26,6 +27,7 @@
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;

import java.io.File;
import java.io.FileInputStream;
import java.net.URI;
import java.net.URL;
Expand All @@ -37,35 +39,74 @@
public class AthModule extends AbstractModule {
@Override
protected void configure() {
Config cfg = new Config();
File userConfig = new File(new File(System.getProperty("user.home")), ".blueocean-ath-config");
if (userConfig.canRead()) {
cfg.loadProps(userConfig);
}
bind(Config.class).toInstance(cfg);

String webDriverType = cfg.getString("webDriverType");
DesiredCapabilities capability;
if ("firefox".equals(webDriverType)) {
capability = DesiredCapabilities.firefox();
} else {
capability = DesiredCapabilities.chrome();
}

DesiredCapabilities capability = DesiredCapabilities.chrome();
LoggingPreferences logPrefs = new LoggingPreferences();
logPrefs.enable(LogType.BROWSER, Level.ALL);
capability.setCapability(CapabilityType.LOGGING_PREFS, logPrefs);

String webDriverUrl = cfg.getString("webDriverUrl", "http://localhost:4444/wd/hub");
String webDriverBrowserSize = cfg.getString("webDriverBrowserSize");

try {
WebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), capability);
WebDriver driver = new RemoteWebDriver(new URL(webDriverUrl), capability);
LocalDriver.setCurrent(driver);

driver = new Augmenter().augment(driver);
driver.manage().window().maximize();
if (webDriverBrowserSize == null) {
driver.manage().window().maximize();
} else {
String[] widthXHeight = webDriverBrowserSize.split("x");
driver.manage().window().setSize(new Dimension(Integer.parseInt(widthXHeight[0]), Integer.parseInt(widthXHeight[1])));
}
driver.manage().deleteAllCookies();
bind(WebDriver.class).toInstance(driver);

String launchUrl = new String(Files.readAllBytes(Paths.get("runner/.blueocean-ath-jenkins-url")));
String launchUrl = cfg.getString("jenkinsUrl");
if (launchUrl == null) {
launchUrl = new String(Files.readAllBytes(Paths.get("runner/.blueocean-ath-jenkins-url")));
}
bindConstant().annotatedWith(BaseUrl.class).to(launchUrl);
LocalDriver.setUrlBase(launchUrl);

JenkinsUser admin = new JenkinsUser(
cfg.getString("adminUsername", "alice"),
cfg.getString("adminPassword", "alice")
);
bind(JenkinsUser.class).toInstance(admin);

CustomJenkinsServer server = new CustomJenkinsServer(new URI(launchUrl), admin);

CustomJenkinsServer server = new CustomJenkinsServer(new URI(launchUrl));
bind(JenkinsServer.class).toInstance(server);
bind(CustomJenkinsServer.class).toInstance(server);

if(server.getComputerSet().getTotalExecutors() < 10) {
server.runScript(
"jenkins.model.Jenkins.getInstance().setNumExecutors(10);\n" +
"jenkins.model.Jenkins.getInstance().save();\n");
}

Properties properties = new Properties();
properties.load(new FileInputStream("live.properties"));
File liveProperties = new File("live.properties");
if (liveProperties.canRead()) {
properties.load(new FileInputStream(liveProperties));
}
bind(Properties.class).annotatedWith(Names.named("live")).toInstance(properties);
} catch (Exception e) {
LocalDriver.destroy();
throw new RuntimeException(e);
}

Expand Down
73 changes: 73 additions & 0 deletions acceptance-tests/src/main/java/io/blueocean/ath/Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package io.blueocean.ath;

import javax.inject.Singleton;
import java.io.File;
import java.io.FileReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
* Really simple property lookup, resolved in order from:
*
* System.getProperty
* environment
* configFile
* def value
*/
@Singleton
public class Config {
private final Map<String, String> props = new HashMap<>();

public Config() {
}

public void loadProps(File configFile) {
try {
Properties props = new Properties();
props.load(new FileReader(configFile));
props.stringPropertyNames().forEach(key -> this.props.put(key, props.getProperty(key)));
} catch(Exception e) {
throw new RuntimeException(e);
}
}

public String getString(String name) {
return getString(name, null);
}

public String getString(String name, String def) {
if (props.containsKey(name)) {
return props.get(name);
}
String envValue = System.getenv(name);
if (envValue != null) {
return envValue;
}
return System.getProperty(name, def);
}

public boolean getBoolean(String name) {
return getBoolean(name, false);
}

public boolean getBoolean(String name, boolean def) {
String prop = getString(name);
if (prop != null) {
return Boolean.parseBoolean(prop);
}
return def;
}

public int getInt(String name) {
return getInt(name, 0);
}

public int getInt(String name, int def) {
String prop = getString(name);
if (prop != null) {
return Integer.parseInt(prop);
}
return def;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.offbytwo.jenkins.JenkinsServer;
import com.offbytwo.jenkins.client.JenkinsHttpClient;
import io.blueocean.ath.pages.classic.LoginPage;
import org.apache.http.client.HttpResponseException;
import org.apache.log4j.Logger;

Expand All @@ -19,11 +18,11 @@ public class CustomJenkinsServer extends JenkinsServer {

protected final JenkinsHttpClient client;

public CustomJenkinsServer(URI serverUri) {
super(serverUri);
public CustomJenkinsServer(URI serverUri, JenkinsUser admin) {
super(serverUri, admin.username, admin.password);
// since JenkinsServer's "client" is private, we must create another one
// use authenticated client so that user's credentials can be accessed
client = new JenkinsHttpClient(serverUri, LoginPage.getUsername(), LoginPage.getPassword());
client = new JenkinsHttpClient(serverUri, admin.username, admin.password);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.blueocean.ath;

/**
* Holds a credential to login with
*/
public class JenkinsUser {
public final String username;
public final String password;

public JenkinsUser(String username, String password) {
this.username = username;
this.password = password;
}
}
151 changes: 151 additions & 0 deletions acceptance-tests/src/main/java/io/blueocean/ath/LocalDriver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package io.blueocean.ath;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import java.util.List;
import java.util.Set;

/**
* Wrapper around an underlying WebDriver that
* consistently handles waits automatically.
*
* Accepts expressions for css and xpath, if the provided lookup starts with a /, XPath is used
*/
public class LocalDriver implements WebDriver {
private static ThreadLocal<WebDriver> CURRENT_WEB_DRIVER = new ThreadLocal<>();

public static void setCurrent(WebDriver driver) {
CURRENT_WEB_DRIVER.set(driver);
}

public static WebDriver getDriver() {
return CURRENT_WEB_DRIVER.get();
}

public static void destroy() {
WebDriver driver = CURRENT_WEB_DRIVER.get();
if (driver != null) {
try {
driver.close();
} catch(Exception e) {
// ignore, this happens when running individual tests sometimes
}
}
}

private static String urlBase;

public static String getUrlBase() {
return urlBase;
}

public static void setUrlBase(String base) {
urlBase = base;
}

/**
* Used for callbacks in a specific browser context
*/
public interface Procedure {
void execute() throws Exception;
}

@Override
public void get(String s) {
getDriver().get(s);
}

@Override
public String getCurrentUrl() {
return getDriver().getCurrentUrl();
}

@Override
public String getTitle() {
return getDriver().getTitle();
}

@Override
public List<WebElement> findElements(By by) {
return new SmartWebElement(getDriver(), by).getElements();
}

@Override
public WebElement findElement(By by) {
return new SmartWebElement(getDriver(), by).getElement();
}

@Override
public String getPageSource() {
return getDriver().getPageSource();
}

@Override
public void close() {
WebDriver driver = getDriver();
if (driver != null) {
try {
driver.close();
} catch(Exception e) {
// ignore, this happens when running individual tests sometimes
}
}
}

@Override
public void quit() {
getDriver().quit();
}

@Override
public Set<String> getWindowHandles() {
return getDriver().getWindowHandles();
}

@Override
public String getWindowHandle() {
return getDriver().getWindowHandle();
}

@Override
public TargetLocator switchTo() {
return getDriver().switchTo();
}

@Override
public Navigation navigate() {
return getDriver().navigate();
}

@Override
public Options manage() {
return getDriver().manage();
}

/**
* Push a specific driver into context and execute the proc
* @param driver new driver in context
* @param proc procedure to execute
*/
public static void use(WebDriver driver, Procedure proc) {
WebDriver previous = CURRENT_WEB_DRIVER.get();
try {
CURRENT_WEB_DRIVER.set(driver);
try {
proc.execute();
} catch(RuntimeException e) {
throw e;
} catch(Exception e) {
throw new RuntimeException(e);
}
} finally {
if (previous == null) {
CURRENT_WEB_DRIVER.remove();
} else {
CURRENT_WEB_DRIVER.set(previous);
}
}
}
}
Loading