As we look at driving a Windows client machine from Jenkins, to run Selenium based browser tests things get a little bit more involved. In this 3rd module of our Building The Test Automation Framework course we step things up a little bit. Nothing we can’t handle though as we take you through each step in detail.
We’re going to cover four key areas:
1. Setting up a Windows Jenkins salve machine
2. Install the test software on the slave machine (e.g. Python and Selenium)
3. Creating a basic Selenium script
4. Running the Selenium Scripts from the Jenkins Master Machine
Once you’ve completed all of these steps you’ll have setup a client Windows AWS machine that will run Selenium tests against our application under test (AUT). As always we’re looking to automate the whole process. So we’ll be configuring our Jenkins server to start the client machine and then control this client machine through the use of the Jenkins slave application.
A few complexities in this module though as Windows User Account Controls (UACs) do their best to prevent us from achieving our goals. We’ll show you some tips and tricks that get round a lot of these issues. Tips and tricks you’ll find invaluable when you come to creating your own Jenkins environments.
What You’ll Learn
In this module we’ll go through the 12 parts listed below looking at the practical aspects of setting up Selenium.
In this session we’re going to configure our system so that we automatically start a Windows test machine that we’ll run a set of Selenium browser tests from. This client windows machine will be automatically started by Jenkins. Once running the Selenium scripts will be started by another Jenkins project.
Once complete we’ll have added the Selenium components to our system as shown below:
However, in order to run these Selenium scripts on a client windows machine we need a desktop terminal session that the scripts will run in. We want to run the test scripts in a real environment and see them running. We don’t want to run them in some headless mode that isn’t a true simulation of what an end user would be doing with the application under test.
Getting Jenkins to create RDP terminal sessions is quite tricky due to the way Windows implements user account control (UAC). So we’ll learn some tricks to get round this and how to really create a set of tests that represent real user actions.
One final thing to mention before we get started. This is a course on building the test automation framework using jenkins. It’s not a course on writing Selenium scripts. So the Selenium scripts we’re using are pretty basic. They server the purpose of implementing this framework and are easy to build on if you want to expand and plugin your own scripts later.
The Tools We’ve Chosen
We’re testing a browser based application so it seems sensible to choose Selenium as the tool to write our automated test cases in. We can get Selenium drivers for a range of different browsers so we’ll be able to provide test coverage against IE, FireFox and Chrome (we could do more but this’ll be adequate for now).
It’s important to point out though that this isn’t a Selenium course. So the Selenium scripts we’re using here are simple, linear and, well basic. This gives the added advantage that it makes things easier to understand. You just need to be aware that in order to scale the actual test cases you’ll probably want to look at improving the way these test cases are written (something we’ll get into in a later course).
So if we’re using Selenium the next question is what language are we going to write our test scripts in. Well “to stop the should it be C# or Java discussion” we discounted those two languages straight off. And because I’m keen on Python that’s what I chose. Then there’s the fact that it’s efficient, fast and easy to learn. Oh and there’s the point that the demand for testers that can code in Python is growing exponentially. So Python it is.
Prerequisites
Right, we need to make sure we have everything setup correctly before we start. First we need to be sure we’ve launched our Windows master machine and that we have an RDP session open.
Make Sure your Windows Master EC2 Instance is Running
If you don’t have your Windows master machine up and running yet then you’ll need to revisit Module 1 and take a look at the section on Running up the Windows Instance.
With the Windows 2008 master machine configured then we’ll need make sure the instance is running and that we have an RDP session open. You can complete these steps with
1. Open your AWS management console, and view your list of Instances (making sure you have the correct Region selected).
2.Once started open an RDP session on this Windows machine.
Then enter the password (you may need your .pem private key file to Decrypt the password if you’ve forgotten it) to open up the desktop session.
Make Sure you have your Private key (.pem file)
Remember back in Module 1 we created our public and private key pairs? Well at that stage you should have saved your private key pair .pem file (e.g. FirstKeyPair.pem) file. You’ll need this private key when configuring Jenkins later.
If you don’t have have this private key you can go back and create a new key pair. Much easier if you can find the one you created in Module 1 though.
Setup a new Security Group for Windows Client
For the Windows client machine it’s best to setup it’s own dedicated security group. We’ll need this as Jenkins connects to this machine with CIFS (Common Internet File System) and WinRM (Windows Remote Management). Both of these require access over specific protocols and ports.
To setup a new security group follow these steps
i. login to your AWS management console
ii. go to your AWS EC2 dashboard
iii. select ‘Security Groups’ in the left hand menu
iv. click on the ‘Create Security Group’ button
v. add the ‘Security Group Name’ – “Windows-client”
vi. add the description – “Windows client machine”
vii. leave the VPC field set to the default
viii. add the following rules then click ‘Create’
Security Group Rules
Inbound: Custom TCP Rule TCP 445 0.0.0.0/0
Inbound: Custom TCP Rule TCP 5985 0.0.0.0/0
Inbound: RDP TCP 3389 0.0.0.0/0
Outbound: All traffic All All 0.0.0.0/0
Part 1: Setup Our Windows Test Machine
Create a Windows 2012 Server Instance in AWS
Four things we need to create this Windows instance:
Microsoft Windows Server 2012 R2 Base – ami-83a5bce2
t2.micro
Name: Windows-Client
Security: default
Back to our EC2 dashboard then:
i. login to your AWS management console
Step 1: go to your AWS EC2 dashboard
Step 2: select the correct region
Step 3: click ‘instances’ in the side menu
Step 4: select the AMI listed above (Microsoft Windows Server 2012 R2 Base )
Step 5: select the Type listed above (t2.micro)
Step 6: accept all the ‘Instance Config’ defaults
Step 7: accept all the ‘Storage’ defaults
Step 8: [optional] add a tag for the Name if you like (e.g. Windows-Client)
Step 9: for the security group we’ll need to:
Step 10a: Select existing security groups
Step 10b: Check the ‘Windows-client’ security group AND
Step 10c: Check the ‘default’ security group
Step 11: Review and then ‘Launch’
Once the new instance is running you can use the EC2 console to put the instance into a “stopped” state. Don’t terminate it, just put it into a stopped state. We’ll start it up again using Jenkins later.
Part 2: Configuring Jenkins to Start A Windows Slave Machine
We’ve already configured Jenkins to run up one slave machine. This slave machine runs our Ubuntu Linux environment that hosts our Application Under Test (AUT) – Rocket Chat. Now we need to add to this environment and create a connection to the Windows slave machine that we’ll run our Selenium browser testing from.
First step is to configure this machine in Jenkins and make sure we can connect to it. We can complete all of this from the Manage Jenkins / Configuration page in the Jenkins Gui.
1. Open up Internet Exporer and type in this URL
2. In the Jenkins home page click on Manage Jenkins -> Configure System
3. At the bottom of the configuration page we need to create a new AMI. We already have our cloud settings configured so this time round we only need to add an additional AMI. So scroll to the bottom of the page and add an AMI
4. Enter the AMI details
Description: Windows-client
AMI ID: <see below>
We’re going to be using this slave machine to run a few different browsers and Selenium. We’ve already created instance and have this running with an AMI that gives us this type of server:
Microsoft Windows Server 2012 R2 Base 64-bit
The current AMI for this is…
ami-83a5bce2
However, this may change as AWS update their AMIs. The quickest way to check this and make sure you have the correct AMI is to
i. login to your AWS management console
ii. go to your AWS EC2 dashboard
iii. select the correct region
iv. click ‘instances’ in the side menu
Whilst you’re on this page it’s worth making a note of the ‘Availability Zone’ that your master Windows Jenkins machine is running in. We’ll need this in the next step. So note down this value…
Then continue with…
v. click the ‘Launch Instance’ button
vi. make sure the ‘Free tier only’ check box is checked
vii. look for the “Microsoft Windows Server 2012 R2 Base” AMI
viii. copy the AMI number (e.g. ami-83a5bce2)
You don’t actually need to launch an ‘instance’ here. You just need to make sure you have the AMI id that is associated with a Windows Server 2012 R2 Base 64 bit machine.
So at the end of this part you should have two pieces of information that we’ll need in a minute:
a. the ‘Availability Zone’ that your master Windows Jenkins machine is running in
b. the AMI id of a windows 64 bit 2012 R2 Base server that Amazon has available for you to create instances from.
Both of these peices of information will be needed in the next part.
5. Click on Check AMI to make sure AWS gives us access to use this AMI
6. Select the ‘T2Micro’ Instance Type (to make sure you stay on the AWS free tier)
7. Enter the Remote User, AMI Type and a few other values leaving everythying else as a default.
EBS Optimized: <un-checked>
Availability Zone: <get-from-aws-account> (*1)
Use Spot Intance: <un-checked>
Security group names: default, Windows-client (*2)
Remote FS root: c:\jenkins
Remote User: Administrator
AMI Type: windows
Windows Admin Password: <leave blank> (*3)
Use HTTPS: <un-checked>
Boot Delay: 3
Labels: SeleniumTestClient
Usage: Utilize this node as much as possible
Idle termination time: 30
Init script: <leave blank>
*1 – set this to the same value as the Availabilty zone that your Windows Master Jenkins machine is running in *2 – we setup the Windows-client security group in the Prerequisites seciton of this module. *3 – we need to leave this blank for now. We’ll come back and update this in minute.
Once you’ve entered these values you should have something like this:
8. Enter the Advanced settings. You’ll need to click the ‘Advanced’ button to expose further settings that we need to update:
Most of these we can leave blank but you will need to update these values:
Stop/Disconnect on Idle Timeout: <checked>
Use private DNS: <checked>
The first setting here stops Jenkins ‘Terminating’ this windows instance if it’s been idle for 30 minutes. With this set if we hit the idle limit this instance will be ‘Stopped’ which preserves all our data.
The second setting for using the private DNS keeps the connection from our master Windows machine (running Jenkins) to our client Windows machine using DNS and hostnames that are private to our AWS Virtual Private Cloud. This just simplifies some of the security complexities for us.
At the bottom of the page you just need to click the ‘Save’ button
9. Start Windows Client Machine from Jenkins
In Jenkins we need to complete these actions to start the AWS Windows client machine instance:
i. go to the Jenkins home page
ii. go to ‘Manage Jenkins’ then ‘Manage Nodes’
On the nodes page we should be able to start our Windows client machine by clicking on ‘Provision via RocketChat Server’ button and selecting ‘Windows-client’
10. Check Windows Client Machine has started
On the Jenkins Nodes page you can click the ‘see log for more details’ link and see the node come up.
You should see a log message that confirms that the machine has been started…
>FINER: Node Windows-client (i-d9b15b01)(i-d9b15b01) is ready
However, you’ll also see that Jenkins is failing to connect and control this machine because we have this message repeating itself…
Waiting for WinRM to come up. Sleeping 10s.
At this stage we’ve started the Windows client machine from Jenkins. However, we’ve only been able to start it. We can’t yet connect to it from Jenkins. Automatically connecting to Windows machines is a little more complicated than our Linux equivalent (where we can just use SSH with our private key). Establishing the connection and control over this machine is what we’ll look at next.
Part 3: Completing the Windows Client Configuration
With the windows client machine started we still need login to it manually with an RDP session, setup some additional configuration manually and then update the Jenkins configuration. Once we’ve done this Jenkins will have complete control over this Windows client machine.
1. Connect Using RDP to the Windows Client machine
Going back to our AWS management console we need to start an RDP session on our Windows Client machine. Follow these steps to open the RDP connection:
i. login to your AWS management console
ii. go to your AWS EC2 dashboard
iii. select ‘Instances’ in the left hand menu
iv. click on the entry for the new Windows Server 2012 instance
v. right click on this instance and select ‘Connect’
vi. select ‘Get Password’ (you’ll need your .pem private key file again)
vii. Decypt the password and save it somewhere safe
viii. click ‘Download Remote Desktop File’
** Make sure you keep a copy of the password – we’ll need it again latert **
At this point you should have got to here…
2. Set Termination Behaviour
Whilst you’re in your AWS account now is probably a good time to set the termination behaviour for a couple of your instances. For instances where you don’t want to lose data it’s worth ‘Enabling Termination Protection’. This just stops you terminating these instances by accident.
i. select the instance
ii. right click on the instance and select ‘Instance Settings’
iii. then select ‘Change Termination Protection’ in the sub menu
iv. in the pop up dialogue box click the ‘Yes, Enable’ button
You’ll want to change this protection setting for both your Windows-master and Windows-client machines. Do NOT change it for your Unix-client machine (we need to terminate this on a regular basis).
3. Configure Windows client to allow CIFS and WinRM access
To allow Jenkins to install it’s Jenkins client on this machine and take control of it we need to update a few settings. We need to enable WinRM (Windows Remote Management) with the following:
i. Open a command prompt
ii. execute the WinRM commands below
WinRM Commands
winrm quickconfig
winrm set winrm/config/service/Auth @{Basic=“true”}
winrm set winrm/config/service @{AllowUnencrypted=“true”}
winrm set winrm/config/winrs @{MaxMemoryPerShellMB=“1024”}
and…
and…
That should give Jenkins the access it needs to connect to the machine. All that’s left now is to install Java so that Jenkins can install it’s client application. It’s this client application that gives Jenkins full control over the machine.
4. Install Java JDK on the Windows client
Jenkins needs Java installed (and Java in the path variable) in order to install and run it’s client/slave application. It’s this app that gives the Jenkins master machine full control over the client and enables it to run Jobs on the client. To install Java we’ll need to:
a. Open Internet Explorer and search for …
Download Java JDK
This should take you to a web page like this…
b. This will present you with this web page where you need to accept the licence agreement then select this package to save…
Note that you might have to change your Internet Explorer security settings here to allow you to download it.
Save this package to the desktop:
The run the installer (as Administrator):
Accept all the defaults as you follow through the install wizard.
c. Last thing is to just check that the install completed successfully and that we have Java in our path.
i. open a NEW command window
ii. type ‘java -version’
iii. type ‘echo %PATH’
iv. check for this in the path: C:\ProgramData\Oracle\Java\javapath
5. Update the Node Configuration in Jenkins
On the Jenkins master machine we just have to update a few configuration settings for the client now. So we’ll need to complete the following actions:
** NOTE: we’re back on our master Jenkins RDP session now! **
i. go to the Jenkins home page (http://localhost:8080)
ii. go to ‘Manage Jenkins’ then ‘Manage Nodes’
On the nodes page we should see our Windows client machine (with an ‘X’ against it as Jenkins has failed to connect with it). From here…
iii. Click the ‘Configure’ link in the side menu
On the Jenkins master machine weiv. Enter the Windows password
From step one above, we decrypted our password for this AWS instance. Hopefully you’ll still have this so that you can enter it here (if not go back to your AWS management console and get the password for this windows-client instance)
On the Jenkins master machine wev. click the save button at the bottom of the screen.
6. Establish Connection Between Jenkins master and Windows Client
At this point we should have everything we need for the master Jenkins machine to communicate with, and take control of, our windows client machine. From our Jenkins master machine follow these steps:
** NOTE: we’re still on our master Jenkins RDP session here! **
i. go to the Jenkins home page (http://localhost:8080)
ii. go to ‘Manage Jenkins’ then ‘Manage Nodes’
On the nodes page we should see our Windows client machine (with an ‘X’ against it as Jenkins has failed to connect with it). From here…
iii. click on the windows-client link
iv. click the ‘Relaunch slave agent’ button
At this point you should see the log file displayed automatically. After a minute or so the log file should start to show messages like this…
>FINER: Node Windows-client <instance-id> is ready
>Connecting to <ip-address> with WinRM as Administrator
>Waiting for WinRM to come up. Sleeping 10s.
>WinRM service responded.
>WinRM should now be ok on Windows-client
>slave.jar sent remotely. Bootstrapping it
>This is a Windows slave
>Slave successfully connected and online
At this point we have our Windows slave machine up and running. It’s running the Jenkins slave Jar too so the Jenkins master machine can control it and send jobs to it.
However, before we move on, let’s talk a little about what happens if you can’t get this connected.
Part 4: What to do when you Can’t Connect the Windows Slave
The connection between the Jenkins master machine and the Jenkins windows slave is established using Windows Remote Management (WinRm). This is installed and running by default when we create our Windows slave instance using the Windows Server 2012 R2 Base AMI.
However, sometimes you may find you run into problems connecting the two machines using WinRm. To see if the connection issue is down to WinRm configuration you can try this on the Jenkins Windows Master machine.
In your AWS account find out what the ‘Internal IP address’ is of the “Client/Slave Windows Machine”. You’ll also need the Administrator password for this machine too.
On the Jenkins master machine open a command terminal
What this does is try to connect to the client machine using WinRm (don’t forget to replace <ip-address-of-client> with the right client ip address). It’s basically simulating what Jenkins tries to do when it connects to the slave machine. Now, if you get this result, or any other connection error, you know you have an issue with your WinRM configuration…
>WSManFault
>Message = The WinRM client cannot process the request.
>Unencrypted traffic is currently disabled in the client
>configuration. Change the client configuration and try
>the request again.
In which case it’s worth trying commands like this on the Jenkins Windows Master machine:
>winrm set winrm/config/client @{AllowUnencrypted=“true”}
>winrm set winrm/config/client/Auth @{Basic=“true”}
This is telling us that the connection was successful. If this is successful then Jenkins should be okay making the WinRm connection now. So you can try going back to Jenkins on the nodes pages and “Relaunching the slave agent”.
WinRm is a complete topic in it’s own right. However, using the commands above may well help you at least identify where the connection issue lies.
If you need to dig deeper into this topic then there’s a lot of helpful information on this page:
Installation and Configuration for Windows Remote Management
Another issue you might run into is slow response times from the slaves. This is especially true when we’re running low tier AWS instances. If you’re seeing the connection succeed then drop out again, there are a couple of options.
First, you could increase the AWS teir that your instance is running on. Of course if you do this you may run up charges and costs as these are unlikely to be on the free teir.
Secondly, you could try turning off the response time check as a temporary fix.
Go to Manage Jenkins -> Manage Nodes -> Configure, and uncheck the “Response time” box. This should stop Jenkins dropping the slave just because it’s not responding fast enough.
Part 5: Installing the Software we need on the Windows Slave
We have the slave Jenkins machine running and under the control of our main Jenkins machine. Now we can deploy some of the software we need to this slave machine so that it can run our Selenium tests. Software packages we’ll need will include:
Chrome
Firefox
Python 3.5
1. Open an RDP session on the Windows 2012 slave machine
i. login to your AWS management console
ii. go to your AWS EC2 dashboard
iii. select ‘Instances’ in the left hand menu
iv. click on the entry for the new Windows Server 2012 instance
v. right click on this instance and select ‘Connect’
vi. click ‘Download Remote Desktop File’
2. On your Windows 2012 Server client machine download and install the following:
Chrome: http://www.google.com/chrome
Firefox: https://www.mozilla.org/en-US/firefox/new/
Python: https://www.python.org/downloads/release/python-351/
(Windows x86-64 executable installer)
I’m not going to take you step by step through this because it should be pretty straight forward. Once you have those three installed we can walk through the process of setting up Selenium and then writing our first Selenium scripts.
3. Check Python is installed correctly.
a. open a command prompt
b. type ‘py’ followed by return
c. you should see “Python 3.5.1 (v3.5.1:37a07cee5969…”
d. type ‘exit()’ to come out of the Python shell
If this didn’t work you’ll have to go back to step 2 above and try re-installing Python again.
Now all we need to do is add the Selenium Python package to our install.
4. Install the Selenium Python package
If Python is installed correctly you should find it installed here…
We need to change directory now and make sure we have ‘pip’ the Python Package and software management tool installed. We’ll need this to install Selenium. So double click on the ‘Scripts’ folder and look for the file/executable ‘pip’.
From a command prompt run this command:
C:\Users\Administrator\AppData\Local\Programs\Python\Python35\Scripts\pip.exe help
This should show you some help information to confirm that pip is installed correctly. From here we need to replace the ‘help’ command with the ‘install’ command to install the Selenium packages. From the command prompt run
So we have Python installed and the Selenium package. We have our browsers installed but we don’t have the Selenium drivers installed for those browsers. Well that’s not strictly true. FireFox comes installed with the Selenium driver but IE and Chrome don’t. So we’re missing these bits…
Next then we need to install the Selenium drivers for IE and Chrome.
5. Install the Chrome Selenium Driver
On our Windows 2012 Slave machine use a browser to search for the ‘Chrome selenium driver’. This should take you to a Url like this…
From here download the latest ChromeDriver, for example:
chromedriver_win32.zip
Extract the exe from the zip file and copy this file to the ‘C:\Windows’ folder.
The only reason we’re copying it to the ‘C:\Windows’ directory is because this directory is in the PATH environment variable already. Which means when we execute it the system will have no problem finding the exe for this driver. You can try this if you like by running this command:
chromedriver.exe
This shows the Chrome driver running and waiting for a connection.
Next then the IE driver.
6. Install the IE Chrome Selenium Driver
Bit more tricky to find this one. However, a hunt on the web for ‘IE Selenium Driver’ should take you to a place like this…
Select the latest folder/version and download the latest IEDriverServer file, for example:
IEDriverServer_Win32_2.50.0.zip
Again, extract the exe from the zip file and copy this file to the ‘C:\Windows’ folder.
One last thing on the IE setup. We need to disable protected mode for all zones:
Then close down IE and we should be ready to go.
Part 6: Create Our First Selenium Script
So at this point we have everything we need on this Windows 2012 slave machine. We just need to create a few Selenium tests and run them locally. Once we have them running locally we can start triggering their execution from the master Jenkins machine.
To begin with we’ll check Python and Selenium can drive all our browsers. We’ll great a short script to open each browser in turn.
1. Open notepad and enter the following script
Save this script to the desktop with the file name ’sel.py’
2. Open a command prompt and run this script
C:\Users\Administrator\Desktop\sel.py
Which should be executed as follows:
Running this should open each browser in turn, go to the Google home page and then close each browser.
This just confirms for us that everything we need is setup correctly on the slave machine. Just need to check we can run this from our Jenkins master machine now.
3. Checking the sel.py script return codes
When Jenkins runs scripts on remote slave machines it determins the success or failure of the job/build based on the return code from the LAST script or command executed. If you run the sel.py script again on the Slave machine then type this at the command prompt:
echo %errorlevel%
In the example below where the script ran successfully we see the error code is ‘0’ which means success. If Jenkins sees this it’ll mark the Job/build as a pass (which is what we want).
Lets change the script slightly so that we make it fail. You can do this in notepad by changing this line…
Note the change in case of ‘IE’. Save this and run the script again. This time we should see a failure
And when we look at the error code we see a ‘1’. This means the script failed. When Jenkins picks up on this it will mark the Job as failed. We going to keep this state whilst we configure Jenkins.
Part 7: Running the Selenium Script from the Jenkins Master Machine
Lets setup the Jenkins master machine to kick off this selenium script on the Slave machine. The Selenium scirpt is configured to fail at the moment so we should see this fail the job first time round. Then we’ll update the Selenium script to fix it and see the job pass. That’ll just confirm for us that we’ve configured all of this correctly.
1. Create a new Job/build task in Jenkins
** We’re back on the Master Jenkins Windows 2008 machine now **
2. Give the new job an item name and select Freestyle project
Restrict where this project can be run: <checked>
Label Expression: SeleniumTestClient
This forces the job to run on our Windows 2012 client/slave machine where we’ve setup our Selenium tests.
At the bottom of the configuration page we need to setup a build step. Click the ‘Add build step’ button and select ‘Execute Windows batch command’. Then add the following command
C:\Users\Administrator\Desktop\sel.py
Then click the ‘save’ button.
4. Run the job and check that it fails
Now we click on ‘Build Now’ in the side menu to kick off this job on our Windows slave machine:
The build should show up in the Build que but because we’ve set it to run on our client machine labeled ‘SeleniumTestClient’ it may take a while for this client to start or for Jenkins to re-establish communications with the client. Once it’s started though you should see this…
And then if you return to the home page (click back to dashboard) you should see this job/build fail.
Click the ‘Console output’ menu item next to the failed build number to check why this has failed. You should see something like this:
Which is what we expected. We had ‘IE’ instead of ‘Ie’ in our script so the script failed with this error message
AttributeError module ‘selenium.webdriver’ has no attribute ‘IE’
And returned an error code of ‘1’ that Jenkins interpreted to mean the job failed.
5. Update the Selenium script on the client machine changing this…
and save the ’sel.py’ file
6. Run the job again and check that it passes
Go back to the home page and click the ‘Bulid now’ icon
This time round we should see a blue button to indicate that the build passed.
Click on the ‘Console Output’ icon again and review the results from the Selenium script run. You should see something like this…
You can see from this that the error level was 0 (e.g. success) and Jenkins used this to mark the job/build as a pass.
Now all we have to do is write some selenium scripts to test our Rocket Chat application and get Jenkins to run these scripts once the build of Rocket Chat has completed.
Part 8: Checking we can Access Rocket Chat from our Windows Client
What we need to do now is run up our application under test, Rocket Chat. Now we already have that scripted in Jenkins and designed to run on a dedicated AWS Linux instance. So lets start out by running this up.
1. Kick off the ‘BuildRocketChatOnNode’ job in Jenkins
So click on the ‘build now’ icon for the Rocket Chat job.
This might take a few minutes to complete but you should see this in Jenkins:
2. Make sure your Windows Selenium test client/slave is running
If you check on your Jenkins dashboard and you see the Windows Client as offline like this…
Then you can bring it back online automatically by running this Jenkins job too
So we’ve started up both Jenkins slave machines automatically from our Jenkins master machine. From our ‘Build Executor Status’ panel we should be seeing something like this…
And of course in our AWS account we should see all three of our instances all up and running together for the first time:
Next we need to make sure our Windows client machine can see the application under test running on our Linux client machine.
3. Check the Windows Client can access the Rocket Chat application on the Linux client
So we’re going to look to establish this link (shown in red below)
Essentially this link is just a browser on the Windows client machine displaying the web page that is being generated by the Rocket Chat application running on our Linux client machine.
Now don’t forget that when these Linux clients run up they pick up a new public Ip address and hostname. So you’ll need to check your AWS account to find the Hots name of the Linux client:
Then taking this host name or Ip address we’ll open up a browser on the windows client machine. We need to bear in mind here that Rocket Chat runs on port 3000 so we’ll need to enter this Url in your browser on the Windows client machine:
So you should get something like this…
At this point we’re ready to write a few Selenium scripts on our Windows client machine that login to Rocket Chat.
Part 9: Writing Some Selenium Tests for Rocket Chat
Now we’re not going to get into how to develop good Selenium scripts in this module. Plenty of good resources on the web that already cover that. What we’ll do is write a login/logout script and run that for each browser type. This will give you enough to expand on as you develop your own environment.
We’re going to take an example directly from the Selenium Python Bindings documentation (found below) and modify this for our purposes:
http://selenium-python.readthedocs.org/getting-started.html
1. Open notepad with the sel.py script and replace the contents with the following script (making sure you get the indentation correct):
We’ve updated this script a little from the example given on the Selenium Python Bindings web site. Most of what this script does is explained on that web site but the few changes we’ve made are detailed below. We can run the command with a call like this:
a. we’re passing in the driver type in the command line. So now we can control which browser we’re testing in. Later we’ll use Jenkins to control which browser we’re testing by getting Jenkins to set this driver type.
b. we’re now passing in the URL and port number in the command line. We’re passing this in as parameter number 2 on the command line (argv[2]). This is because down the line we’ll need Jenkins to pass this value in each time it runs the job. The host name for the server running the AUT will change so Jenkins will need to deal with this.
c. we’re using XPATH and Class Names to identify objects on the web page and then interact with those objects. We’d recommend using Firefox with the FirePath extension to identify objects in your applications. Makes it all much simpler.
d. we have conditional logic that looks to see if this is a NEW install of Rocket Chat. If it is then we need to create the account first before we do the login. If it’s NOT a new install then we use an existing Admin account and login without creating a new account.
e. the %errorcode% returned from running this script is set directly by the success or failure of the unit tests. If the unit test asserts fail it’s an %errorcode% of ‘1’ which tells Jenkins that the job has failed. If it’s an %errorcode% of ‘0’ this indicates a pass and Jenkins will report the job/build as a pass.
And that’s it for now on the Selenium script side of things. Just enough to test that the application is running, that we can create a new account and that we can login/logout.
Part 10: Running an RDP/RDC Session on our Master Jenkins Machine
The next challenge (and it’s kind of a big one) is to get our master Jenkins machine to open up an RDP/RDC session to our client windows machine that runs our Selenium scripts. We are going to run GUI tests on a jenkins windows slave with a remote desktop connection running on the Jenkins master machine.
We want this because the Selenium scripts are designed to run on a terminal with the browsers running. We could run some browser tests in a headless mode but this comes with it’s own set of issues and isn’t really a close enough representation of what the end user will be doing (in my opinion). So we need to get Jenkins to create an RDP/RDC terminal on the Jenkins master machine automatically.
This is fraught with issues. But there is a neat solution…even if it is a bit convoluted.
The key problem we need to overcome is that Jenkins is running on the master machine as a service. And with Windows 7 and later ‘running as a service’ means you can’t start applications (e.g. an RDP session) on that machine directly from that service. You run into all sorts of issues with User Account Control Setting issues.
The way round this then is to run a Jenkins slave process on the Master machine. This slave jenkins process is run from a user account. Having it run from a user account (using a batch file or something similar) means that this Jenkins slave process does have the right account privileges to run applications (e.g. RDP sessions). You then get the Jenkins master to call the Jenkins slave (which is on the same machine) and run up the RDP session. And once the RDP session is running we can then get Jenkins to run the Selenium scripts.
Here’s how we do this then…
1. Create the jenkins working directory
First create a jenkins directory on the master machine, so that you have this directory…
C:\jenkins
Which looks like this…
2. Download the Jenkins slave.jar on the Jenkins master machine
In a borwser on the master machine enter this Url
Once the file has downloaded open the download folder and copy the slave.jar file to the C:\jenkins directory. You can use a command like this if you want
3. Configure this slave as a node in Jenkins
In Jenkins we need to setup this machine so that it is seen as a slave machine. To do this go to ‘Manage Jenkins’ and then ‘Manage Nodes’
From here we can click on ‘New Node’
We’ll call the node “SlaveOnMaster” (to indicate that we’re running a Jenkins slave on the Jenkins master machine) and select ‘Dumb Slave’
On the configuration page we’ll need to set a few fields
Name: SlaveOnMaster
Description: <blank>
# of executors: 1
Remote root directory: C:\jenkins
Labels: SlaveOnMaster
Usage: utilize this node as much as possible
Launch method: Launch slave via execution of command on the Master
Launch command: <blank>
Availability: Keep this slave on-line as much as possible
A few things to point out here. We have the label set to ‘SlaveOnMaster’ because we want to force specific jobs to run on this machine. We have left the launch command blank. We DON’T want this Jenkins master process to launch the slave Jenkins process. We want to do this manually (more on this in a minute). It’s lanuching this slave process outside of the Jenkins master process that’ll give us the privileges we need to automatically start an RDP session.
So this should give us this:
Once we save this we should have:
With the red cross indicating that this Slave isn’t connected. So next we need to connect it!
4. Run the Jenkins Salve.jar process
Now we need to run this Jenkins slave process and get it to connect to the Jenkins master process (both of which are running on the same machine).
We need to create a batch file called ‘jenkinsSlave.bat’, add the following command and save the batch file to the desktop:
Make sure this is all on 1 line. It should look like this:
What this batch file does is lanuch the Jenkins slave process using the Java executable. This will then connect to the Jenkins master process.
To create the connection double click and run this batch file.
You should then see this in the Nodes dashboard in Jenkins:
Note: if you want you can create a shortcut for this .bat file then locate the Startup folder and save this batch file shortcut in the startup folder. This way it’ll automatically start when the server starts up.
5. Create the Jenkins Job to start the RDP terminal
Now Jenkins can talk to the Slave process we can get jenkins to lanuch the RDP session automatically. We just need to create the job
Go back to the Jenkins home page and select ‘New Item’
Call the new job ‘RunClientRDPSession’ and select ‘Freestyle project’
Only things we need to update on this now job are:
Restrict where this project can be run: SlaveOnMaster
So we should have…
And then select ‘Add build step’ and configure as follows:
For now we’re going to hardcode the hostname of our client windows machine that will run our selenium tests. We’ll come back and add this as a parameter later.
The first line of this command sets up our master machine connection to the windows host so that it connects automatically with the Administorator account. You will need to specify the Admin password in this command.
The second line starts the RDP session with the window heigh and width parameters defined. And the last line just makes sure that Jenkins doesn’t kill the RDP session we’ve just started when the commands have completed.
Save the job and then we’re ready to check that we can automatically start an RDP session from Jenkins.
6. Run the RunClientRDPSession job
Go back to the Jenkins home page and run the RunClientRDPSession job.
You should see Jenkins open an RDP session on the windows Jenkins machine automatically.
7. Check the Selenium tests run in the RDP session
You should be able to run the selenium tests on the client machine now
And you should see those tests running in the RDP session that you’e just opened with Jenkins too.
Part 11: Closing the RDP/RDC Session on our Master Jenkins Machine
Bit simpler this bit. Once we’ve opened the RDP session and then run our Selenium tests we’ll want to close the RDP session. We’ll need to close it because if we run the process again we don’t want to end up with 2 RDP sessions open.
1. So at this stage you should be able to create a new project by clicking ‘New Item’ on the Jenkins home page.
2. Then use the Item name:
Item Name: CloseClientRDPSession
3.We don’t need to restrict where this project can be run as we want it to run on the master machine that has the RDP terminal session open. So all we need to set is the batch command to run.
4. Then add an ‘Execute Windows batch command’ build step and enter the following script:
cmd /c taskkill /IM mstsc.exe
So we’ll have…
5. Run this project (click the ‘build now’ icon) and just make sure it closes the current RDP terminal session that’s open.
With that in place it’s just a question of linking all the projects together.
Part 12: Running the AUT build followed by the Selenium Tests
We now have the 4 things we need in place to get this up and running fully. We have the Jenkins project that installs and starts the application under test. We have the project that opens the client RDP terminal session on the master machine. And we have the project that starts and runs the Selenium tests on the client. Lastly we have the project that closes the client RDP terminal session. All we need to do now is string them together.
First we’ll link the RDP session opening (RunClientRDPSession) to the Selenium test execution (RunSeleniumTests) and the RDP close session (CloseClientRDPSession). Then we’ll link in the application under test install at the start of that (BuildRocketChatOnNode).
1. Modidfy the RunSeleniumTest project by clicking on ‘Configure’ for the project
2. Update the RunSeleniumTest Build Trigger settings so that we have…
Build after other projects are build: <checked>
Projects to watch: RunClientRDPSession
Trigger only if build is stable: <set>
Like this:
This needs to be set so that the RunSeleniumTests project gets kicked off after other project is built. It only gets kicked off IF the RunClientRDPSession is stable. If there RDP session isn’t stable and doesn’t open no point in running the Selenium tests. So in this case we’re checking that RunClientRDPSession project has completed successfully.
3. Update the CloseClientRDPSession Build Trigger to:
Build after other projects are build: <checked>
Projects to watch: RunSeleniumTest
Trigger even if the build fails: <set>
Like this:
Note that we’ve set this to ‘Trigger even if the build fails’. We want the RDP terminal session to close even if the Selenium tests fail. That’s so the terminal always closes and is ready for the next Selenium test run.
Save these project updates then we can test that this works.
4. Test that the project dependencies work
First make sure you close the RDP session on the master machine. Then go back to the main Jenkins dashboard. Kick off the RunClientRDPSession project manually
Then what you should see of course is the RunClientRDPSession project execute followed directly by the RunClientRDPSession and then finally the CloseClientRDPSession project run. Our Jenkins dashboard should show the results as follows:
Now all we need to do is pull in the initial project that builds and installs the AUT (BuildRocketChatOnNode).
5. Add condition that starts Client RDP Session when ATU Build is complete
At this stage just one last thing to add to this chain of events. When we run the build/install of the AUT (the Jenkins RunClientRDPSession project) we need the completion of this job to trigger RDP session creation (RunClientRDPSession) and the selenium tests (RunSeleniumTests)
We need to update the RunClientRDPSession Build Trigger to
Build after other projects are build: <checked>
Projects to watch: RunClientRDPSession
Trigger only if build is stable: <set>
Like this:
Only problem we have now is that when ever we do a complete install of the AUT and Amazon AWS creates a new instance we’ll have a new Url for the AUT. So we need to pick the hostname and Url out of the BuildRocketChatOnNode project and pass that to the subsequent jobs.
6. Determin hostname/Url of AUT and pass to downstream projects
So the next bit gets interesting. The problem is that our ‘RunSeleniumTests’ job has the host name the AUT is running on hardcoded. For example:
This is going to cause problems when we start the whole process from scratch and we run up a new AWS instance. That new instance will have a new hostname and our hard coded ‘RunSeleniumTests’ job won’t work. So we need to parameterise these commands. This requires a number of things in Jenkins
a. Jenkins 'BuildRocketChatOnNode' job to record it's AUTs public host name for the host it is run on
b. Jenkins master machine to know the AUTs public hostname
c. Jenkins 'RunSeleniumTests' job to pick up the hostname as a parameter
Probably many ways to approach this (for example using some of the Jenkins parameterization plugins). We’re going to approach it in the simplest way I know using the the ‘Environment Injector Plugin’, ‘Copy Artifact Plugin’ and the in-built ‘Archive Artifacts’ capability in Jenkins.
https://wiki.jenkins-ci.org/display/JENKINS/EnvInject+Pluginhttps://wiki.jenkins-ci.org/display/JENKINS/Copy+Artifact+Plugin
What these plugins allows us to do is create a file on the slave running the AUT that contains a variable with the public host name in. This file then gets pulled back to the master jenkins machine. This file is then copied from the ‘BuildRocketChatOnNode’ workspace to the ‘RunSeleniumTests’ workspace. When we come to run the ‘RunSeleniumTests’ job, this job reads in the file and uses the public host name as a parameter.
First we need to install the ‘Environment Injector Plugin’ and ‘Copy Artifact Plugin’.
i. go to the Jenkins home page
ii. go to ‘Manage Jenkins’ then ‘Manage Plugins’
iii. click the ‘Available’ tab and search for ‘Environment Injector Plugin’
iv. check the check box for this plugin
v. search for the ‘Copy Artifact Plugin’
vi. check the check box for this plugin
v. scroll to the bottom of the page and click the ‘Install without restart’ button
vi. wait for the success indication and then go back to the dashboard
From here we need to do three things. First, create the file that contains the public host name. Second, configure the ‘BuildRocketChatOnNode’ job to pull the file back from the slave to the master jenkins machine and keep it as an archived file. Third, configure the ‘RunSeleniumTests’ job to read the file and use the public host name value.
First then we need to update the ‘BuildRocketChatOnNode’ so that it creates a file with our public host name in. Go back to the Jenkins home page and configure the ‘BuildRocketChatOnNode’ job.
At the bottom of this page, in the Execute Shell Command section you need to add these two line at the bottom of the script:
> cd ~/workspace/BuildRocketChatOnNode/
> echo "PUBLIC_HOSTNAME=http://$(curl http://169.254.169.254/latest/meta-data/public-hostname 2>/dev/null):3000" > publicHostname.txt
So it should look something like this…
All this command does is find out the public host name from one of the Amazon servers, concatenate this with the string ‘http://’ and the ‘:3000’ port number. It then puts this information into a file called ‘publicHostname.txt’. The contents of which will look something like this…
Next we need to get this ‘publicHostname.txt’ file back from the workspace area on the linux slave to the workspace on the Jenkins master machine and archive the file. To do this we just use the in built build step to ‘Archive the artifacts’ post build action.
To configure this configure the ‘BuildRocketChatOnNode’ job again…
At the bottom of the configuration screen add a ‘Post Build Action’ to ‘Archive the artifacts’
In the ‘Archive the artifacts’ section that is added enter the name of our file containing the Host Name of the AUT machine. This file name is ‘publicHostname.txt’
Save the job. What this will do is pull the publicHostname.txt file back from the AUT machine and save it on the Jenkins master machine in the project workspace. Then all we need to do is copy this file from ‘BuildRocketChatOnNode’ workspace to the ‘RunSeleniumTests’ workspace. We can do this by editing the ‘RunSeleniumTests’ job from the Jenkins home page:
And then adding a ‘Copy artifacts from another project’ build step…
Then complete the following fields:
Project name: BuildRocketChatOnNode
Which build: Latest successful build
Artifacts to copy: publicHostname.txt
Like so…
Now we have the file containing the host name available to this job. Next we need this job to process the file at run time. For this we need to ‘Inject environment variables’. So we’ll add another build step for ‘Inject environment variables’:
Add the following field data:
Properties File Path: publicHostname.txt
Like so…
When this job executes on the Windows slave machine it will set the environment variable …
All we need now is for the part of the job that runs the selenium tests to use this hostname. For that we just edit the existing ‘Windows Batch Command’ changing it from:
We now have 3 build steps in this Job. It’s really important that they run in the right order though. You’ll notice on the build steps that you can ‘grab’ the handle and change the order the steps. For example…
To get this working correctly you MUST put the build steps in this order…
Copy artifacts from another project
Inject environment variables
Execute Windows batch command
In short you need the publicHostname.txt artifact available to the job before you can inject it. Once publicHostname.txt is available to the job the ‘Inject environement varialbes’ build step can read the file and make the PUBLIC_HOSTNAME environment variable available to the job. Then the windows batch command can use the %PUBLIC_HOSTNAME% variable when the commands are executed.
Save the changes you’ve made to the job and return to the Jenkins home page. Run the ‘BuildRocketChatOnNode’ job which will then trigger the ‘RunClientRDPSession’ job follwed by the ‘RunSeleniumTests’ job automtically.
With a bit of luck you should see the BuildRocketChatOnNode job create the publicHostname.txt file. That publicHostname.txt copied for use in the RunSeleniumTests and these test complete successfully.
You may find the first Selenium test against IE failed. This will probably be down to the trusted sites setup in IE. In which case you’ll want to define the amazonaws.com domain as a trusted site so the ‘warning message’ doesn’t stop the execution. You can do this on these dialogue boxes:
All we need to do now is run this right from the start which Jenkins creating a new instances of the Linux machine (with a new public hostname).
7. Test the whole workflow
That’s everything configured. All we need to do now is test the whole process. To do this we’ll
i. Go to the Amazon EC2 dashboard
ii. Select ‘Instances’ in menu
iii. ‘Terminate’ the Linux Ubuntu client
iv. ‘Stop’ the Windows client
Make sure you get these the right way round. We don’t want to Terminate the Windows client
Now we can go to the Jenkins dashboard and kick of the full process. To do this click ‘Build Now’ for the ‘BuildrocketChatOnNode’ project.
This should create the Linux EC2 instance, build the AUT and install Rocket Chat. If that completes successfully then the next projects in the chain will start that run the RDP session and kick off the Selenium tests. Last but not least the RDP terminal session is closed once the Selenium tests are finished. Job done.
Conclusion
So we’ve configured Jenkins to start a slave Windows machine that will run our browser tests. We’ve install the software we needed to run our browser tests (e.g. a set of different browsers, Python and Selenium). We’ve created our first Selenium script and checked that this runs against our application under test.
With the automated tests in place we’ve then configured Jenkins to run these scripts auotmatically on our Windows client machine. We’ve worked out how to run RDP/RDC terminal sessions on our Master Jenkins machine so that these Selenium tests can run in a real environment (not just some headless mode). In order to do this we’ve gone through some quite complex configuration steps in this module. Most of the complexity needed to get round Windows User Account Control (UAC).
With all the steps/projects created in Jenkins we’ve then completed the simple process of chainning all our Jenkins projects together. And hopefully on running this for the first time we’ve seen everything run end to end. Right from starting our client AWS machines, building/installing our AUT and running our automated tests.
What we’ve completed in this module is the crux of building out our test automation framework. Yes it’s a little tricky in places but once running you have a setup that you can expand and develop further. You know all the key tricks for building this out to test your own appplications now. You just need to plugin your application, write your own Selenium tests and plug those tests into this framwork too.