/*
* The MIT License
*
* Copyright (c) 2010, InfraDNA, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.saucelabs.sauce_ondemand.driver;
import com.saucelabs.saucerest.SauceREST;
import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium;
import sun.misc.BASE64Encoder;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
/**
* @author Kohsuke Kawaguchi
*/
class SeleniumImpl extends DefaultSelenium implements SauceOnDemandSelenium, Selenium {
/**
* {@link DefaultSelenium} throw away the session ID as soon as the {@link #stop()}
* is called, so we'll store it aside.
*/
private String lastSessionId;
private String jobName;
private final Credential credential;
SeleniumImpl(String serverHost, int serverPort, String browserStartCommand, String browserURL, Credential credential, String jobName) {
super(serverHost, serverPort, browserStartCommand, browserURL);
this.credential = credential;
this.jobName = jobName;
}
@Override
public void start() {
super.start();
dumpSessionId();
}
@Override
public void start(String optionsString) {
super.start(optionsString);
dumpSessionId();
}
@Override
public void start(Object optionsObject) {
super.start(optionsObject);
dumpSessionId();
}
/**
* Dump the session ID, so that it can be captured by the CI server.
*/
private void dumpSessionId() {
lastSessionId = getSessionId();
System.out.println("SauceOnDemandSessionID=" + lastSessionId + " job-name=" + jobName);
}
public String getSessionId() {
try {
Field f = commandProcessor.getClass().getDeclaredField("sessionId");
f.setAccessible(true);
Object id = f.get(commandProcessor);
if (id != null) return id.toString();
return lastSessionId;
} catch (NoSuchFieldException e) {
// failed to retrieve the session ID
} catch (IllegalAccessException e) {
// failed to retrieve the session ID
}
return null;
}
public String getSessionIdValue() {
return getSessionId();
}
public Credential getCredential() {
return credential;
}
public URL getSeleniumServerLogFile() throws IOException {
return getFileURL("selenium-server.log");
}
public URL getVideo() throws IOException {
return getFileURL("video.flv");
}
private URL getFileURL(String fileName) throws MalformedURLException {
// userinfo in URL doesn't result in the BASIC auth, so in this method we won't set the credential.
return new URL(MessageFormat.format("https://saucelabs.com/rest/{0}/jobs/{1}/results/{2}",
credential.getUsername(), lastSessionId, fileName));
}
public InputStream getSeleniumServerLogFileInputStream() throws IOException {
return openWithAuth(getSeleniumServerLogFile());
}
public InputStream getVideoInputStream() throws IOException {
return openWithAuth(getVideo());
}
private InputStream openWithAuth(URL url) throws IOException {
URLConnection con = url.openConnection();
//Handle long strings encoded using BASE64Encoder - see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6947917
BASE64Encoder encoder = new BASE64Encoder() {
@Override
protected int bytesPerLine() {
return 9999;
}
};
String encodedAuthorization = encoder.encode(
(credential.getUsername() + ":" + credential.getKey()).getBytes());
con.setRequestProperty("Authorization", "Basic " + encodedAuthorization);
return con.getInputStream();
}
public void jobPassed() throws IOException {
Map<String, Object> updates = new HashMap<String, Object>();
updates.put("passed", true);
updateJobInfo(updates);
}
private void updateJobInfo(Map<String, Object> updates) throws IOException {
SauceREST sauceREST = new SauceREST(credential.getUsername(), credential.getKey());
sauceREST.updateJobInfo(lastSessionId, updates);
}
public void jobFailed() throws IOException {
Map<String, Object> updates = new HashMap<String, Object>();
updates.put("passed", false);
updateJobInfo(updates);
}
public void setBuildNumber(String buildNumber) throws IOException {
Map<String, Object> updates = new HashMap<String, Object>();
updates.put("build", buildNumber);
updateJobInfo(updates);
}
public void setJobName(String jobName) throws IOException {
Map<String, Object> updates = new HashMap<String, Object>();
updates.put("name", jobName);
updateJobInfo(updates);
}
}