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

Experiment/selenium logs #1412

Merged
merged 34 commits into from
Oct 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7ace9de
use chrome instead of firefox and enable console logs integration
Sep 21, 2017
4002984
direct Selenium Chrome's console logs to log4j
Sep 21, 2017
4f0b122
suppress superfluous log entries
Sep 21, 2017
60cca2c
try to improve error handling / logging code especially for Selenium …
Sep 22, 2017
2744998
another attempt to make Chrome + Selenium error stack readable
Sep 25, 2017
4013f1b
another attempt to make Chrome + Selenium error stack readable
Sep 26, 2017
f8e73b1
make the error logging code a bit more explicit and fall back to logg…
Oct 3, 2017
9d595b2
Merge branch 'master' into experiment/selenium-logs
Oct 3, 2017
8865161
switch nightwatch config to use chrome
Oct 3, 2017
af4c8de
update the "deletePipeline" logic to delete by repo name instead of o…
Oct 4, 2017
d0f62f0
hide editor's Cancel and Save buttons until the pipeline is loaded
Oct 4, 2017
05d72b9
just remove the browser name altogether from messaging
Oct 4, 2017
cede23b
try to fix an issue in ATH where pipeline scripts were not properly s…
Oct 4, 2017
ebcf1b5
use the latest Chrome, since the rest of the world will too
Oct 4, 2017
c9f0bf7
add some TODOs around areas of test fragility
Oct 4, 2017
27b37ba
Merge branch 'master' into experiment/selenium-logs
Oct 4, 2017
48928b3
wait for Branches tab to be visible before clicking it
Oct 5, 2017
f03aabf
asserting the location immediately could fail since a redirect needs …
Oct 5, 2017
00934a3
wait for Branches tab to be visible before clicking it
Oct 5, 2017
9e30db6
be more specific about which "replay" button to click
Oct 5, 2017
b113970
add another note about a flaky assertion / test
Oct 5, 2017
6c5aec2
more tweaks to get nightwatch tests to cooperate
Oct 9, 2017
e620e63
more tweaks to get nightwatch tests to cooperate
Oct 9, 2017
17cc48a
hide warning about password field on non-https page
Oct 9, 2017
34faca8
try to address an error in CI about span.IconButton-text not being cl…
Oct 9, 2017
21f7d43
remove unused obsolete element corresponding to the old "single repo"…
Oct 9, 2017
20782ff
try to fix an apparent timing issue where "create pipeline" would be …
Oct 9, 2017
ea4e0c6
use string concat for logging unhandled errors since selenium likes t…
Oct 9, 2017
2bfb300
Merge branch 'master' into experiment/selenium-logs
Oct 10, 2017
f296d07
lock version of docker chrome image
Oct 11, 2017
5226edc
introduce "click" utility methods that wait for element to be clickab…
Oct 12, 2017
d3b5372
use an anchor instead of span for sheet's back button with the hope i…
Oct 12, 2017
fe13d06
implement retry logic for click
Oct 12, 2017
f4e6174
Merge branch 'master' into experiment/selenium-logs
Oct 18, 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
8 changes: 4 additions & 4 deletions acceptance-tests/nightwatch.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module.exports = (function (settings) {
var url = require('url');
var launchUrl;
var netaddr = require('network-address');

if (process.env.LAUNCH_URL) {
//
// This allows you to run the tests against a Jenkins instance of
Expand All @@ -29,7 +29,7 @@ module.exports = (function (settings) {

launchUrl = fs.readFileSync(jenkins_url_file, 'utf8');
}

// Replace localhost addresses with the actual IP, allowing it
// to work inside a docker container running on the host.
launchUrl = launchUrl.replace('localhost', netaddr());
Expand All @@ -46,7 +46,7 @@ module.exports = (function (settings) {

console.log('Jenkins running at: ' + settings.test_settings.default.launch_url);
console.log(" NOTE:");
console.log(" Selenium and the browser (Firefox) are running in a docker");
console.log(" Selenium and the browser are running in a docker");
console.log(" container that also has VNC. This allows you to connect if");
console.log(" you'd like to look at the browser while the tests run.");
console.log(" Simple run:");
Expand All @@ -59,6 +59,6 @@ module.exports = (function (settings) {
if (fs.existsSync('target/.selenium_server_provided')) {
settings.selenium.start_process = false;
}

return settings;
})(require('./src/main/nightwatch.json'));
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/
public class DevRunner extends BOJUnitTest {

@Test
public void runAndStayRunning() throws Exception {
System.out.println("");
Expand All @@ -50,7 +50,7 @@ public void runAndStayRunning() throws Exception {
System.out.println(" See http://nightwatchjs.org/");
System.out.println("");
System.out.println(" NOTE:");
System.out.println(" Selenium and the browser (Firefox) are running in a docker");
System.out.println(" Selenium and the browser are running in a docker");
System.out.println(" container that also has VNC. This allows you to connect if");
System.out.println(" you'd like to look at the browser while the tests run.");
System.out.println(" Simple run:");
Expand All @@ -59,7 +59,7 @@ public void runAndStayRunning() throws Exception {
System.out.println("------------------------------------------------------------------------------------");
System.out.println("");
System.out.println("ctrl-c to exit...");

while(true) {
Thread.sleep(1000);
}
Expand Down
4 changes: 2 additions & 2 deletions acceptance-tests/runner/scripts/start-selenium.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ $SCRIPT_DIR/stop-selenium.sh
echo ""
echo " Starting Selenium Docker container..."
echo ""
docker run -d --name blueo-selenium -p 15900:5900 -p 4444:4444 -e no_proxy=localhost selenium/standalone-firefox-debug:2.53.0 > /dev/null
docker run -d --name blueo-selenium -p 15900:5900 -p 4444:4444 -e no_proxy=localhost selenium/standalone-chrome-debug:3.6.0-bromine > /dev/null

# Output the containers bridge network IP to file
SELENIUM_IP=`docker inspect -f '{{ .NetworkSettings.IPAddress }}' blueo-selenium`
Expand All @@ -15,7 +15,7 @@ echo $SELENIUM_IP > ./target/.selenium_ip

echo ""
echo "**************************************************************"
echo "**** Docker container with Selenium, Firefox and VNC running."
echo "**** Docker container with Selenium, browser and VNC running."
echo "**** Selenium server listening on $SELENIUM_IP:4444"
echo "**** "
echo "**** To connect and view with VNC, run:"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.logging.LogEntries;
import org.openqa.selenium.logging.LogEntry;
import org.openqa.selenium.remote.ScreenshotException;

import java.io.File;
Expand Down Expand Up @@ -75,8 +77,10 @@ public void evaluate() throws Throwable {

try {
next.evaluate();
outputConsoleLogs();
} catch (Exception e) {
writeScreenShotCause(e, test, method);
outputConsoleLogs();
throw e;
}

Expand Down Expand Up @@ -114,7 +118,16 @@ private void writeScreenShotCause(Throwable t, Object test, FrameworkMethod meth
FileUtils.copyFile(scrFile, file);
logger.info("Wrote screenshot to " + file.getAbsolutePath());
}
}
}

private void outputConsoleLogs() {
logger.info("browser console output below:");
WebDriver driver = injector.getInstance(WebDriver.class);
LogEntries logs = driver.manage().logs().get("browser");
for (LogEntry entry : logs) {
LogEntryLogger.recordLogEntry(entry);
}
}


@Override
Expand Down Expand Up @@ -174,4 +187,5 @@ public synchronized Throwable fillInStackTrace() {
return this;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
import io.blueocean.ath.pages.blue.RunDetailsArtifactsPage;
import io.blueocean.ath.pages.blue.RunDetailsPipelinePage;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.logging.LoggingPreferences;
import org.openqa.selenium.remote.Augmenter;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;

Expand All @@ -29,12 +32,16 @@
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Properties;
import java.util.logging.Level;

public class AthModule extends AbstractModule {
@Override
protected void configure() {

DesiredCapabilities capability = DesiredCapabilities.firefox();
DesiredCapabilities capability = DesiredCapabilities.chrome();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should really pass this in from tests so we can run on multiple browsers at some point

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to take a look at selenium-grid as it's the "selenium way" of firing off multiple test runs in different browsers.

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

try {
WebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), capability);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package io.blueocean.ath;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.log4j.Logger;
import org.openqa.selenium.logging.LogEntry;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
* Writes a Selenium LogEntry to log4j
* @author cliffmeyers
*/
class LogEntryLogger {
private static final Logger logger = Logger.getLogger(LogEntryLogger.class);
private static final ObjectMapper jsonMapper = new ObjectMapper();
private static final TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {};

static void recordLogEntry(LogEntry entry) {
if (!logger.isInfoEnabled() || isSuperfluousLogEntry(entry)) {
return;
}

String time;
String level;
String text;

try {
// handle messages written by @jenkins-cd/js-logging
Map<String, Object> messageJson = jsonMapper.readValue(entry.getMessage(), typeRef);
Map<String, Object> message = (Map<String, Object>) messageJson.get("message");
time = String.valueOf(message.get("timestamp"));
level = String.valueOf(message.get("level"));
text = String.valueOf(message.get("text"));
} catch (IOException e) {
// handle messages written natively by console.error|warn|log|debug
time = String.valueOf(entry.getTimestamp());
level = String.valueOf(entry.getLevel());
text = entry.getMessage();
}

logger.info(String.format("%s - %s - %s", time, level, text));
}

// special handling to suppress some repetitive logging messages that are not helpful
private static final String MESSAGE_JS_LOGGING = "@jenkins-cd/logging is explained";
private static final String MESSAGE_CHROME_CONSOLE = "Chrome displays console errors";
private static final String MESSAGE_PASSWORD_INSECURE = "page includes a password or credit card input";

static boolean isSuperfluousLogEntry(LogEntry entry) {
String message = entry.getMessage();
return message.contains(MESSAGE_JS_LOGGING) || message.contains(MESSAGE_CHROME_CONSOLE) ||
message.contains(MESSAGE_PASSWORD_INSECURE);
}
}
27 changes: 26 additions & 1 deletion acceptance-tests/src/main/java/io/blueocean/ath/WaitUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.NotFoundException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
Expand All @@ -18,7 +19,7 @@
@Singleton
public class WaitUtil {
private Logger logger = Logger.getLogger(WaitUtil.class);

private static final int RETRY_COUNT = 2;

private WebDriver driver;

Expand Down Expand Up @@ -82,4 +83,28 @@ public <T> Function<WebDriver, Integer> orVisible(Function<WebDriver, WebElement
};
}

/**
* Click the element specified by the locator.
* Will retry click for 'element not clickable' exceptions
* @param by
*/
public void click(By by) {
for (int i = 0; i < RETRY_COUNT + 1; i++) {
try {
until(ExpectedConditions.elementToBeClickable(by)).click();
if (i > 0) {
logger.info(String.format("retry click successful for %s", by.toString()));
}
return;
} catch (WebDriverException ex) {
if (ex.getMessage().contains("is not clickable at point")) {
logger.warn(String.format("%s not clickable: will retry click", by.toString()));
logger.debug("exception: " + ex.getMessage());
} else {
throw ex;
}
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void simplePipeline(String newBranch) {
wait.until(By.cssSelector("button.btn-primary.add")).click();
wait.until(By.xpath("//*[text()='Print Message']")).click();
wait.until(By.cssSelector("input.TextInput-control")).sendKeys("hi there");
wait.until(By.xpath("(//span[@class='back-from-sheet'])[2]")).click();
wait.click(By.xpath("(//a[@class='back-from-sheet'])[2]"));
wait.until(By.xpath("//*[text()='Save']")).click();
wait.until(By.cssSelector("textarea[placeholder=\"What changed?\"]")).sendKeys("Simple pipeline");
if(!Strings.isNullOrEmpty(newBranch)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public GitCreationPage(WebDriver driver) {
}

public GitCreationPage clickGitCreationOption() {
wait.until(By.xpath("//span[text()='Git']")).click();
wait.until(By.cssSelector(".scm-provider-list .git-creation")).click();
logger.info("Selected git creation");
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import io.blueocean.ath.api.classic.ClassicJobApi;
import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
Expand Down Expand Up @@ -35,14 +34,11 @@ public GithubCreationPage(WebDriver driver) {
@FindBy(css = ".button-connect")
public WebElement connectButton;

@FindBy(css = ".button-single-repo")
public WebElement singlePipelineBtn;

@FindBy(css = ".repo-list input")
public WebElement pipelineSearchInput;

@FindBy(css = ".button-create")
public WebElement createBtn;
public WebElement createPipelineButton;

@Inject
@BaseUrl
Expand Down Expand Up @@ -111,18 +107,26 @@ public void selectPipelineToCreate(String pipeline){
logger.info("Selected pipeline to create");
}

public void clickCreatePipelineButton() {
wait.until(ExpectedConditions.elementToBeClickable(createPipelineButton)).click();
}

public By emptyRepositoryCreateButton = By.cssSelector(".jenkins-pipeline-create-missing-jenkinsfile > div > button");

public void createPipeline(String apikey, String org, String pipeline) throws IOException {
createPipeline(apikey, org, pipeline, false);
}
public void createPipeline(String apiKey, String org, String pipeline, boolean createJenkinsFile) throws IOException {
beginCreationFlow(org);
beginCreationFlow(pipeline);
completeCreationFlow(apiKey, org, pipeline, createJenkinsFile);
}

public void beginCreationFlow(String org) throws IOException {
jobApi.deletePipeline(org);
/**
* @param jobName name of job to be created
* @throws IOException
*/
public void beginCreationFlow(String jobName) throws IOException {
jobApi.deletePipeline(jobName);
navigateToCreation();
selectGithubCreation();
}
Expand All @@ -139,8 +143,7 @@ public void completeCreationFlow(String apiKey, String org, String pipeline, boo
logger.info("Select a repo to create");

selectPipelineToCreate(pipeline);

wait.until(createBtn).click();
clickCreatePipelineButton();

if(createJenkinsFile) {
wait.until(ExpectedConditions.urlContains("pipeline-editor"), 30000);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ module.exports.commands = [{
this.waitForRunVisible(pipeline, runId);
const resultRowSelector = activityRowSelector(pipeline, runId);
this.waitForElementVisible(`${resultRowSelector} .failure`);
},
},

/**
* Wait for a specific run to appear in the activity table as unstable
Expand Down Expand Up @@ -133,19 +133,19 @@ module.exports.commands = [{
* Inspect that result screen runs, shows a stage graph, and completes.
*/
assertStageGraphShows: function() {
//check results look kosher:
this.waitForElementVisible('.progress-spinner.running');
this.waitForElementVisible('.BasicHeader--running');

this.waitForElementVisible('.pipeline-node-selected');
this.waitForElementVisible('.download-log-button');
this.waitForElementVisible('.pipeline-selection-highlight');
this.waitForElementVisible('.pipeline-connector');
this.waitForElementVisible('.pipeline-node-hittarget');
this.waitForElementVisible('.BasicHeader--success');
//check results look kosher:
this.waitForElementVisible('.progress-spinner.running');
this.waitForElementVisible('.BasicHeader--running');

this.waitForElementVisible('.pipeline-node-selected');
this.waitForElementVisible('.download-log-button');
this.waitForElementVisible('.pipeline-selection-highlight');
// in Chrome, 'Visible' seems to fail but 'Present' works ok
this.waitForElementPresent('.pipeline-connector');
this.waitForElementPresent('.pipeline-node-hittarget');
this.waitForElementVisible('.BasicHeader--success');
},

/**
* Click css selector of a specific tab
* @param tab {string} the tab we want to select
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,9 +434,8 @@ module.exports.commands = [{
*/
clickReRunButton: function () {
var self = this;
const browser = this.api;
self.waitForElementVisible('.replay-button');
self.click('.replay-button');
self.waitForElementVisible('.ResultPageHeader-run .replay-button');
self.click('.ResultPageHeader-run .replay-button');
return self;
}

Expand Down
Loading