Github: Forking and keeping your fork in sync

A fork is a snapshot of a repository. You can fork any public repository on Github.

Forking a repository

The process of forking itself is trivial. Navigate to any public github repository and click on ‘Fork’ on the top right.

Cloning your fork

From the forked repository, copy the https clone url and run the git clone command to create a local copy of your fork

git clone https://github.com/YOUR-USERNAME/REPO

Configuring a remote for your fork

If you are going to maintain your fork, you will need to periodically sync changes that are being made in the original or upstream repository. In order to do this, you must configure a remote that points to this original or upstream repository

git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPO

Verify the upstream repository you have specified

git remote -v

origin    https://github.com/YOUR_USERNAME/YOUR_FORK.git (fetch)
origin    https://github.com/YOUR_USERNAME/YOUR_FORK.git (push)
upstream  https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git (fetch)
upstream  https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git (push)

Syncing your fork
Bring the commits to the master branch of the original repo. Fetching it will bring the commits and keep it in upstream/master
git fetch upstream

Checkout your local master
git checkout master

Now merge the changes from upstream/master into your local master
git merge upstream/master

If your local branch did not have any changes, git will do a fast-forward else the merge will fail and you will be required to either commit your changes, stash them or move them to a separate branch before completing the merge.

References:
https://help.github.com/articles/fork-a-repo/
https://help.github.com/articles/syncing-a-fork/
https://help.github.com/articles/configuring-a-remote-for-a-fork/

Publishing local jar to your maven/m2 local repository

You will need to do this if you have a local jar file that is not in the Maven central repository and you need the maven build to work. This will also be useful if you are behind a firewall and do not have external access.

  • Download the jar file or scp the jar file to the build machine
  • At the same directory as the jar file, run the following command to install the jar to the local maven repository

mvn install:install-file -DgroupId=<GROUP_ID> -DartifactId=<ARTIFACT_ID> -Dversion=<VERSION> -Dpackaging=jar -Dfile=<LOCAL_PATH_FOR_JAR> -DgeneratePom=true

  • Now when you run your maven goals, it will not look for this specific jar file in any external repository.

Further if you want your Eclipse to start using this jar from your local repository

  • Eclipse Luna on a Mac, Window > Show View > Other > Maven > Maven Repositories > Local Repositories > Local Repository
  • Right click for the context menu and rebuild index

It should now show up if you try to add this dependency in your pom.xml

Publishing or Uploading a jar to Maven Central

I am assuming your project is already on Github. If not on Github, I would highly recommend moving to Github.

Initial Setup

Sonatype open source software repository hosting (OSSRH) provides repository hosting services to open source projects. The initial setup requires some carefully choreographed steps. The subsequent iterations then become fairly trivial.

  • Create a login or use an existing login you may have to log on to your Sonatype JIRA account
  • Create a new project ticket providing the groupId and the artifactId. It is recommended that you pick your groupId as your top level domain so that you do not end up having to create a JIRA ticket for every subsequent project under this domain. For example, use com.eveningsamurai as groupId instead of com.eveningsamurai.symphony
  • Once the JIRA ticket is created, the maintainers of Sonatype will get back to you, fairly quickly I might add, with the repository urls to which you can push the snapshot and release jar files.

Setting up your pom.xml

As part of your deployment, you are required to include a pom file. The requirements are documented in depth and we will be going over them briefly.

The pom needs the correct project coordinates and human readable information.Make sure you keep the ‘-SNAPSHOT’ appended to the version. It is required for the maven release plugin and will be removed when deploying to the release repository.

<modelVersion>4.0.0</modelVersion>
<groupId>com.eveningsamurai.symphony</groupId>
<artifactId>symphony</artifactId>
<version>0.2.5-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Symphony</name>
<description>Unofficial Java wrapper for the Searchlight Conductor API</description>
<url>https://github.com/eveningsamurai/symphony</url>

Add the following xml tags as well

<licenses>
<developers>

Since we are using Github as our SCM, add the following snippet for scm. Pay particular attention to the remote location being specified below. It should match with the output of git remote. If you are using https access use as below else if you are using ssh access then use the git@github.com format as specified here


$ git remote -v
origin https://github.com/eveningsamurai/symphony.git (fetch)
origin https://github.com/eveningsamurai/symphony.git (push)

  <scm>
    <connection>
       scm:git:https://github.com/eveningsamurai/symphony.git
    </connection>
    <developerConnection>
       scm:git:https://github.com/eveningsamurai/symphony.git
    </developerConnection>
    <url>
      https://github.com/eveningsamurai/symphony.git
    </url>
  </scm>

Another thing to do with regards to SCM is to create a SSH key and add the public key to your github account. If you haven’t done it before, this post explains how to do it.

GPG signing of your artifacts

I used the GPG suite to generate the gpg key pair. It provides an intuitive interface to generate the keys and upload it to a public server. You will find good documentation on getting this done. Once you have generated the key pair and distributed it, you need to sign your artifacts with the maven gpg plugin. This is put in a profile such that it gets activated when doing a deploy and not otherwise. Without this I was running into an error during the later stages saying “Cannot obtain passphrase in batch mode”

   <profiles>
      <profile>
         <id>release-sign-artifacts</id>
         <activation>
            <property>
               <name>performRelease</name>
               <value>true</value>
            </property>
         </activation>
         <build>
            <plugins>
           <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-gpg-plugin</artifactId>
             <version>1.4</version>
             <executions>
               <execution>
                 <id>sign-artifacts</id>
                 <phase>verify</phase>
                 <goals>
                   <goal>sign</goal>
                 </goals>
               </execution>
             </executions>
             <configuration>
                <keyname>75C56291</keyname>
             </configuration>
           </plugin>
        </plugins>
        </build>
     </profile>
   </profiles>

The keyname you see up there should be from the key pair you generated using the GPG suite. It is listed under the Key Id column in the UI.

The settings.xml file needs to updated with the keyname and the passphrase you provided during the generation process if you do not want to provide it at run time

   <profile>
      <id>gpg</id>
      <properties>
         <gpg.keyname>75C56291</gpg.keyname>
         <gpg.passphrase>*******</gpg.passphrase>
      </properties>
   </profile>

Setting up distribution management and credentials to the SonaType Nexus repository

Add the distributionManagement section to the pom file to setup the nexus snapshots and the nexus release repository url’s provided to you in the JIRA ticket resolution by SonaType

   <distributionManagement>
     <snapshotRepository>
       <id>nexus-snapshots</id>
       <url>https://oss.sonatype.org/content/repositories/snapshots</url>
     </snapshotRepository>
     <repository>
       <id>nexus-releases</id>
    <url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>
     </repository>
  <distributionManagement>

Again you need to add the corresponding credentials in the settings.xml file. These credentials are the same that you used for logging in to SonaType JIRA. Further note that the id for the servers below matches the id for the repositories specified above under distributionManagement

    
    <server>
      <id>nexus-snapshots</id>
      <username>******</username>
      <password>******</password>
    </server>
    <server>
      <id>nexus-releases</id>
      <username>******</username>
      <password>******</password>
    </server>    

Supplying Javadoc and Sources

You are required to submit the javadoc and the sources jar file. This can be done by including the maven javadocs plugin and the maven sources plugin in the pom file

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-source-plugin</artifactId>
        <version>2.2.1</version>
        <executions>
          <execution>
            <id>attach-sources</id>
            <goals>
              <goal>jar-no-fork</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-javadoc-plugin</artifactId>
        <version>2.9</version>
        <executions>
          <execution>
            <id>attach-javadocs</id>
            <goals>
              <goal>jar</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

Setting up the release plugin

The maven release plugin can be used to automate the changes to the Maven POM files, run sanity checks, the SCM operations required and the actual deployment execution. However we need to override a couple of dependencies in the release plugin to fix an issue with the later versions of git (1.9+ ?) where -SNAPSHOT version is not being converted to the release(no -SNAPSHOT) version during the release process.

     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-release-plugin</artifactId>
       <version>2.5.2</version>
       <configuration>
          <tagNameFormat>v@{project.version}</tagNameFormat>
       </configuration>
      <dependencies>
         <dependency>
                  <groupId>org.apache.maven.scm</groupId>
                  <artifactId>maven-scm-api</artifactId>
                  <version>1.9.1</version>
              </dependency>
              <dependency>
                  <groupId>org.apache.maven.scm</groupId>
                  <artifactId>maven-scm-provider-gitexe</artifactId>
                  <version>1.9.1</version>
              </dependency>
      </dependencies>
     </plugin>

Upload to repository

  • Make sure you have committed all changes to Github before you begin the process of uploading artifacts to the repositories. The release plugin does a diff against the HEAD and will complain if there are unchecked changes in your local repository.
  • To sign your artifacts and upload them to the snapshot repository simply run
    mvn clean deploy -DperformRelease=true
  • To upload your project to the staging repository, run the mvn goals as below
    mvn release:clean release:prepare release:perform
  • If you run into errors during the release process, you can do a
    mvn release:rollback

    to get back into the original state and fix any issues. Additionally if you are reusing the version numbers then take note to delete the tags from your git repo that the release plugin creates else the next time you rerun the release prepare goal you will run into errors.

  • The artifact is now available in the staging repository. Login to OSSRH, select the Staging Repositories from the left hand navigation and filter by your groupId e.g. comeveningsamurai-1006
  • Download the artifact and test it one last time to ensure that it is what you want to push. If it is not you can drop the staging repository using the menu on the top and rerun the deployment process.

Promoting artifacts from staging to Maven Central

We are almost there, we need to promote the artifacts that were uploaded from staging to Maven Central. You can do this via the browser following their detailed instructions (you can also do this via the command line using the nexus staging plugin or the maven repository plugin but that is not something I have explored)

Finally put in a comment on your JIRA ticket that you pushed your first release into the staging repository and they will setup a sync of your artifacts to Maven Central. Typically within a few hours you should see your artifact on Maven Central

We can now call this done! Congratulations!

Mobile Web Automation with Appium

Mobile Web Automation with Appium

Ideally you are working on a Mac which will allow you to try out both the iOS and the Android flavors of mobile test automation

Building Blocks

Appium

Install NodeJS using brew or from source. Using the node package manager(npm) install WebDriver and then download, install and run the Appium app.

iOS

If you want to automate a web application on iOS that uses Safari it is pretty straightforward to do.
The only thing you need to get right is the Xcode version and the iOS version. For the Appium version I was using 0.17.6, I was able to make do with Xcode 4.6.3 and iOS 6.0

Android

This is a little more involved to setup and configure

  •  Download the Android SDK
  • Download the Android Developer Tools(ADT) for an existing IDE and install (assumes you have an existing Eclipse setup)
  • Add ANDROID_HOME to your .bash_profile and update the PATH
    export ANDROID_HOME=<android sdk path>
    export PATH=$ANDROID_HOME/platform_tools:$PATH
  • Start the Android bridge(adb) server
    adb start-server
  • Launch the Android Virtual Device(avd) from ANDROID_HOME/tools
    ./android avd

Get the latest version of the Chrome browser from the Google playstore (has to be from a real device because you cannot install the Playstore apk on a virtual device).

  • adb shell pm list packages #get chrome package name
  • adb shell pm path <chrome package name> #get package path
  • adb pull <path + chrome package name>

The chrome apk should now be available on your local file system

Now you will need to install the Chrome apk on your virtual device. For that, lets disconnect the real device and start up a device emulator. It can be any device but in order for the chrome apk install to work, the device needs to run on an ARM processor.

  • Create the virtual device from the AVD screen and launch the emulator
  • Install the Chrome apk downloaded earlier on the virtual device
    adb install <local chrome apk path>

In order for Appium to be able to launch Chrome on the emulator, we need to downgrade the ChromeDriver being used by Appium. Download ChromeDriver v2.2 or v2.3 and overwrite the ChromeDriver being used by Appium at this location

  • ChromeDriver location: /Applications/Appium.app/Contents/Resources/node_modules/appium/build/chromedriver/mac/chromedriver

You are now ready to automate a web application using Chrome on an Android device. While this is a bit more involved than the iOS setup, you need to do this only once and it will work as is for a real device as well. Compare this to the work that needs to be done to get a developer account for iOS real device testing and also to get a signing certificate so that it can be pushed to the app store.

Automation tests

Launch the Appium server from the Appium app and point the RemoteWebDriver to the server location.  Once this is done, you can write your automation tests as you would for any web application.

Setup the iOS RemoteWebDriver


DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("device","iPad Simulator");
capabilities.setCapability("app","safari");
driver = new RemoteWebDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
driver.get("http://www.google.com");
System.out.println("iPad Title is: " + driver.getTitle());


DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("device","iPhone Simulator");
capabilities.setCapability("app","safari");
driver = new RemoteWebDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
driver.get("http://www.google.com");
System.out.println("iPhone Title is: " + driver.getTitle());

Setup the Android RemoteWebDriver


DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setPlatform(Platform.ANDROID);
capabilities.setCapability("device", "android");
capabilities.setCapability("app", "chrome");
driver = new RemoteWebDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
driver.get("http://www.google.com");
System.out.println("Android Title is: " + driver.getTitle());

Dummynet

Description

Dummynet is a live network emulation tool used for applications like bandwidth and delay management. Dummynet runs within the operating system  using the concept of pipes to implement bandwidth, delay and loss rate among other things. Its internally managed by ipfw which is the user interface for dummynet

Installation

Dummynet was developed by researchers from the University of Pisa, Italy. It is available for *ix and windows operating systems. However for Windows, the one drawback is that in its original form it is not digitally signed. So Windows Vista forward, even though you are allowed to install the application, Windows does not allow you to run it.

Enter, WPT

The author of WPT (which also uses Dummynet for network emulation), went through the effort of getting the application digitally signed and also porting it over to the 64 bit version of Windows(I might be wrong on the 64bit porting part!)

Process

  • Download the latest version of WPT from: https://code.google.com/p/webpagetest/downloads/list
  • If you are installing on 64-bit Windows, right-click on  “testmode.cmd” in the c:\webpagetest\dummynet\64bit folder and select “Run as Administrator”.
  • Reboot the system to enable testmode.  If you do not run this then traffic shaping will not work after a reboot.
  • Set the properties for the network adapter being used
    • Control Panel and search for adapters
    • View network connections
    • R-click on the network connection being used and select Properties
    • Click Install and add service
    • Click on ‘Have Disk’ and navigate to the location based on 32bit or 64bit Windows: <wpt folder\agent\dummynet\32 or 64bit\netipfw>
    • Select the ipfw+dummynet service  and click on any subsequent alerts
  • Dummynet should now be setup on your system

Dummynet

Its easy to test out how dummynet works for bandwidth management

 

  • Open up the terminal and navigate to the same wpt download location:  <wpt folder\agent\dummynet\32 or 64bit>
  • Run these commands to create a pipe for TCP traffic, list out the ipfw rules to confirm the pipe has been created and then set the bandwidth limit to the pipe
  • From a browser, navigate to: http://www.speedtest.net and test out your connection. Confirm that you get the download speed pretty close to what you set using dummynet
  • This confirms that your downstream connection is now set to 5Mbps
  • To clear the bandwidth limit run this command from the command line: ipfw.exe flush and confirm ‘y’
  • If you need to manage both downstream and upstream, fear not Smile, this can be done as well
  • I
  • From a browser, again navigate to: http://www.speedtest.net and test out your connection. Confirm that both the upstream and downstream are set to 5Mbps

 

 

Resources

Dummynet: http://info.iet.unipi.it/~luigi/dummynet/

Speedtest: http://www.speedtest.net

WPT: https://sites.google.com/a/webpagetest.org/docs/private-instances

Rails deployment with Capistrano

Deployment with Capistrano

Capistrano is most often used for deployment of Rails application. It uses a simple DSL similar to Rake that allows you to define roles to machines and any additional tasks that need to run during deployment.

Here I will walk you through a Capistrano deploy for a simple Rails application residing in your local machine to a single web server. I am assuming this is a simple Rails app that runs on just Webrick even though it is never advisable to do the same for a production setup.

Installing Capistrano

If you are using a Gemfile, you can just add the gems below and do a bundle install. Else install the gems manually from the command line.

gem install capistrano
gem install capistrano-ext

Capistrano assumes that you have SSH access to the server you are deploying to. If you do not then Capistrano is not going to work for you.

Getting setup with Capistrano

Navigate to the root of yours Rails app and ‘capify’ it.

capify .

This will create a file called Capfile(like Rakefile) in your project root. In addition it will also create a deploy.rb in your config folder.

Working with Capistrano

In the deploy.rb, you can begin setting up your application for deploy

set :application, "deploy_demo"

Capistrano comes with a number of recipes to connect to different repos, like Git, SVN and Perforce. However the setup for synch up different repositories is a bit more involved. Here, I am assuming that you are using one of these version control systems and your local rails app has been updated to a state fit for deploy, and all you need to do is copy the application over to the remote server.
So lets go ahead and set the source control to none and deploy mechanism to copy.

set :scm, :none
set :deploy_via, :copy

Specify the user name and password for ssh access and the path to deploy to on the remote server. Also set the use_sudo to false, if you do not want to deploy the application as root.

set :user, "username"
set :password, "password"
set :deploy_to, "/home/user/apps"
set :use_sudo, false

While we are going to deploy to a single box, we can the ability to deploy to multiple environments. This is where the capistrano-ext  gem is going to come handy.
Include multistage at the top of the deploy.rb file

require 'capistrano/ext/mulitstage'

And while you are there add a couple of other includes for rvmrc and Bundler support as well.

require 'rvm/capistrano'
require 'bundler/capistrano'

Now specify your environments or stages. For me its just going to be qa for now. I have also set the default environment to qa.

set :stages, %w(qa)
set :default_stage, "qa"

This does it as far as deploy.rb goes. We still need to add a config file for qa stage. This is done in a qa.rb file inside the config/deploy folder.

In this config file, specify the different roles and set the repository to the current project root.

role :web, "server"
role :app, "server"
role :db, "server", primary: true

set :repository, "."

Rubber hits the road

Capistrano needs to create an initial directory structure for deployments. This is done as a one time task from the project root

cap qa deploy:setup

or
cap deploy:setup

Once this is done, let Capistrano run checks to verify it has everything it needs

cap deploy:check

If you do not see any errors, then you can try out the deploy. For a first time deploy, it is suggested to go with

cap deploy:cold

For subsequent deploys you can just do

cap deploy

Additional Configurations

  • If you want your assets copied over as well, load these 2 recipes in the deploy.rb
load 'deploy'
load 'deploy/assets'
  • If RVM is throwing a ‘No value for $TERM and no -T specified’ error add this environment variable to your Capfile
default_environment["TERM"] = "xterm"
  • If Capistrano complains about a missing Rake gem and you know it should be present, add these settings to your deploy file
set :rvm_ruby_string, "local"
set :rvm_type, :user
  • If you are deploying via a proxy then this needs to be set in your Capfile
default_environment["http_proxy"] = 'http proxy:80'
default_environment["https_proxy"] = 'https proxy:80'
  • Adding deploy hooks to stop, start a server

Capistrano provides hooks that you can define as tasks within the deploy.rb file that will restart a web server or run other custom scripts. For                 our simple Rails app that uses Webrick we can do something like this

pid_file = "/home/#{user}/apps/#{application}/tmp/pids/server.pid"
namespace :deploy do
  task :start do
    run "cd apps/#{application}/current; rails s -e test"
  end

  task :stop do
    run "kill -s QUIT `cat #{pid_file}`" if File.exists?(pid_file)
  end

  task :restart do
    stop
    sleep 2
    start
  end
end
  • If you see errors complaining about rvm-shell not found, add this to your deploy.rb
set :default_shell, "/bin/bash -l"
  • If you notice error relating to gnutar being not available you can switch to using zip compression which should be available by default on *nix systems.
set :copy_compression, :zip

Changing HTTP Headers using Fiddler

I have previously talked about using the modify_headers extension in Firefox to set custom headers using the WebDriver. I also mention that the one major drawback is this can only be done with FirefoxDriver. So what if, you need a solution to work across the different browsers.

We explored using Fiddler running on the Selenium nodes to modify the headers based on the tests, and it turns out that it is pretty trivial to do it using Fiddler.

Modifying Fiddler Rules

Fiddler maintains its rules in a CustomRules.js file. This can be accessed from the Fiddler Rules menu > Customize Rules. We can modify this rules file from our Java code to set the desired http header and since Fiddler is acting as the local proxy, it will work for any network connection meaning all browsers.

   public static List rulesOnDisk;
   public static File file = new File("C:\\Users\\QETester\\Documents\\Fiddler2\\Scripts\\CustomRules.js");

   @BeforeTest
   public void setUp() {
      try {
         Scanner existingRules = new Scanner(file);
         rulesOnDisk = new ArrayList();
         while(existingRules.hasNextLine()){
            rulesOnDisk.add(existingRules.nextLine());
         }
         existingRules.close();
         PrintStream newRules = new PrintStream(file);
         for(String str: rulesOnDisk){
            if(str.matches(".*static.*function.*OnBeforeRequest.*")){
               String headerName = String.format("oSession.oRequest[\"headerName\"] = \"%s\";", "headerValue");
               newRules.println(headerName);
            }
            newRules.println(str);
         }
         newRules.close();
      } catch (FileNotFoundException e) {
         e.printStackTrace();
      }
   }

What the script above is doing is, passing the header name and value to the session request variable. Any request you now make through Chrome, Firefox or actually any browser is going to use this header name and value pair.

Changing HTTP headers for a Selenium WebDriver request

We recently got into a tangle, where our A/B testing tool was not providing us much support in terms of production smoke/sanity testing and we would end up in situations where our production automation tests would periodically fail whenever a multi variant test was run.

After having multi hour sessions with support, we finally figured out that there was indeed a way to test the control and different variants by setting appropriate http headers. Enter the Selenium WebDriver. The Selenium RC used to support setting of headers and such but the webdriver backers apparently thought it against their philosophy to encourage such an approach(I personally disagree but perhaps its for an another day).

After much googling, we finally narrowed down on 2 approaches to resolve this issue

  • Using a Firefox browser extension that would modify the headers for you
  • Using a reverse proxy, like the Browser Mob Proxy

We had trouble setting up the BMP, since we ourselves are behind a corporate proxy. So modify headers extension was what was left for us. I have previously talked about using the netHttp extension to capture network traffic. The approach here is pretty similar. 

Loading the extension

Just download the firefox extension, *.xpi and include that somewhere in your project. Add that to your Firefox profile as below

  FirefoxProfile profile = new FirefoxProfile();
  File modifyHeaders = new File(System.getProperty("user.dir") + "/resources/modify_headers.xpi");
  profile.setEnableNativeEvents(false); 
  try {
    profile.addExtension(modifyHeaders); 
  } catch (IOException e) {
    e.printStackTrace(); 
  }

Setting the extension preferences

The next step after loading the extension, is to actually set the preferences that we need to be set. For example below, I specify that I want 1 http header to be set, the header name, the header value(which could be dynamically coming from some api call) and then finally enabling the extension. This allows the extension to be loaded when webdriver kicks of Firefox and sets it in the active mode along with the http header.

   profile.setPreference("modifyheaders.headers.count", 1);
   profile.setPreference("modifyheaders.headers.action0", "Add");
   profile.setPreference("modifyheaders.headers.name0", "sox");
   profile.setPreference("modifyheaders.headers.value0", "305471");
   profile.setPreference("modifyheaders.headers.enabled0", true);
   profile.setPreference("modifyheaders.config.active", true);
   profile.setPreference("modifyheaders.config.alwaysOn", true);

Setting DesiredCapabilities

To wrap it up set firefox capability to use the profile above and launch Firefox

  DesiredCapabilities capabilities = new DesiredCapabilities();
  capabilities.setBrowserName("firefox");
  capabilities.setPlatform(org.openqa.selenium.Platform.ANY);
  capabilities.setCapability(FirefoxDriver.PROFILE, profile);

  WebDriver driver = new FirefoxDriver(capabilities);
  driver.get("http://website.com");

The complete code below

@Test(invocationCount=1)
public void launchWebsite() {
  FirefoxProfile profile = new FirefoxProfile();
  File modifyHeaders = new File(System.getProperty("user.dir") + "/resources/modify_headers.xpi");
  profile.setEnableNativeEvents(false); 
  try {
    profile.addExtension(modifyHeaders); 
  } catch (IOException e) {
    e.printStackTrace(); 
  }

   profile.setPreference("modifyheaders.headers.count", 1);
   profile.setPreference("modifyheaders.headers.action0", "Add");
   profile.setPreference("modifyheaders.headers.name0", "sox");
   profile.setPreference("modifyheaders.headers.value0", "305471");
   profile.setPreference("modifyheaders.headers.enabled0", true);
   profile.setPreference("modifyheaders.config.active", true);
   profile.setPreference("modifyheaders.config.alwaysOn", true);

   DesiredCapabilities capabilities = new DesiredCapabilities();
   capabilities.setBrowserName("firefox");
   capabilities.setPlatform(org.openqa.selenium.Platform.ANY);
   capabilities.setCapability(FirefoxDriver.PROFILE, profile);

   WebDriver driver = new FirefoxDriver(capabilities);
   driver.get("http://website.com");
}

Hope this helps. The one huge drawback with this approach I see is that this will work with Firefox only. While I am able to load a corresponding extension in Chrome, I have not found a way to actually turn on the extension and set the http header value at runtime.

Selenium Waits

Adding waits to Selenium WebDriver tests

There are a few ways you can add waits when writing your Selenium WebDriver automation tests.

1) Incorrect Waits 😉

A couple of approaches here are actually considered bad coding practices but only including them here for completeness.


long currentTime = System.currentTimeMillis();
while(System.currentTimeMillis() < (currentTime + 5000)) {}

------------------------------------------------------------
try {	
	Thread.sleep(1000); //time in milliseconds
} catch(InterruptedException ie){
	ie.printStackTrace();
}

2) Implicit waits

Implicit waits are set for the lifetime of the WebDriver object. With an implicit wait set, WebDriver polls the DOM every 500ms till the element is found or you reach the time specified


WebDriver driver = new FirefoxDriver()
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

3) Explicit waits

Explicit waits are set for a particular element. They are especially useful when you have a large number of assertions that check for absence of elements. With absence of elements, an implicit wait would wait the time set for every find element clause.
With explicit waits however, along with ExpectedConditions we can quickly check for absence of elements and move on with our tests


WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 30);

driver.get("http://www.google.com");
By searchField = By.name("q");
wait.until(ExpectedConditions.presenceOfElementLocated(searchField));

4) FluentWait

There is another instance of wait available for the Java instance of the WebDriver. The Selenium documentation describes it best “Each FluentWait instance defines the maximum amount of time to wait for a condition, as well as the frequency with which to check the condition. Furthermore, the user may configure the wait to ignore specific types of exceptions whilst waiting, such as NoSuchElementExceptions when searching for an element on the page.”


Wait wait = new FluentWait(driver)
       .withTimeout(30, SECONDS)
       .pollingEvery(5, SECONDS)
       .ignoring(NoSuchElementException.class);

WebElement searchField = wait.until(new Function() {
  public WebElement apply(WebDriver driver) {
     return driver.findElement(By.name("q"));
  }
});

Resources

http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp
http://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html
http://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/support/ui/FluentWait.html

Jira REST api example with Ruby

Jira offers a number of REST api’s to access/manipulate information. Below is a quick example of accessing the information using Ruby

Pre-Requisites

Jira expects authentication with each api call. The easiest way to do this would be to authenticate via basic auth in the HTTP request you make.

Command line request check

curl -u username:password http://jira.company.com/rest/api/latest/issue/ABC-123.json

or

wget –user=username –password=password http://jira.company.com/rest/api/latest/issue/ABC-123.json

You should get back a file named ABC-123.json

Ruby Client


require 'rest_client'
require 'json'

project_key = "ABC"
jira_url = "http://username:password@jira.company.com/rest/api/2/search?"
# latest 5 issues from a project with 'Major' priority
filter = "maxResults=5&fields=summary,status,resolution&jql=project+%3D+%22#{project_key}%22+AND+priority+%3D+%22Major%22"

response = RestClient.get(jira_url+filter)
if(response.code != 200)
  raise "Error with the http request!"
end

data = JSON.parse(response.body)
data['issues'].each do |issue|
  puts "Key: #{issue['key']}, Summary: #{issue['fields']['summary']"
end

I was getting a lot of URI invalid errors with the way I was constructing the filters. A good approach to consider in that case is you login to jira via your browser and construct a search filter using the JQL query you want and save it. You then query for this url http://jira.company.com/rest/api/2/filter/favourite in your browser. Then look for the value of searchUrl param in the response and you have got the url that Jira expects for your search query.

Resources:
JIRA apis list: https://docs.atlassian.com/jira/REST/latest/#idp583456
Other Clients: https://confluence.atlassian.com/display/DOCSPRINT/The+Simplest+Possible+JIRA+REST+Examples