Showing posts with label Cucumber. Show all posts
Showing posts with label Cucumber. Show all posts

Thursday, July 6, 2017

Intro to Docker for Developers: How to Run your Rails App on Docker

Docker in a Nutshell First of all what is Docker? Let’s chew on the Wikipedia definition to start: 

“Docker is an open-source project that automates the deployment of applications inside software containers, by providing an additional layer of abstraction and automation of operating-system-level virtualization on Linux.[2] Docker uses resource isolation features of the Linux kernel such ascgroups and kernel namespaces to allow independent "containers" to run within a single Linux instance, avoiding the overhead of starting and maintaining virtual machines.[3]”

From a developer perspective Docker promises us the opportunity to forget about the “it works in my local environment but not in production” problem as well as the “it works on my Ubuntu machine but not on my buddy’s Mac three feet away” scenario. 

Now, with the magic of a definition file, it is super easy to port an app between environments: from local to lab, and later to production. Docker is incredibly fast and thanks to the use of some linux kernel features like namespaces, we have isolation for filesystem, networks and processes. 


This consistency is an incredible opportunity for developers, but it’s an especially big win for our users: with Docker we can reduce highly disruptive “environmental issues” to almost zero percent. 

Did I just say the word disruptive? Oh right, container revolution, blah blah. :)

Step #1: Prepare Your Infrastructure / Server Environment



Let’s “dockerize” a basic Rails app.This is what the app looks like. It was created using “Rails new Rails-App” (if you don’t have Rails you can just follow the installation instructions here) 

First, you need to have Docker running. To do so, you can just check the docker documentation, which is really quite easy to follow. Choose your platform, follow the instructions, and voilĂ ! 

Once installed, check that the Docker daemon is running properly by typing:

$ docker -v

Docker version 1.7.0, build 0baf609 (this will probably change based on the installation type/platform you have chosen)

Step #2: Build Your Image


Next up we need to build our Rails image. Docker uses a definition file to describe what the environment will contain. Usually it’s named Dockerfile (you can use a different name also), so for simplicity let’s create a file in our app directory called “Dockerfile” and add a few lines in there (gist):

# Base image FROM ruby:latest 
ENV HOME /home/rails/webapp 

# Install PGsql dependencies and js engine 
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs 

WORKDIR $HOME 

# Install gems 
ADD Gemfile* $HOME/ 
RUN bundle install 

# Add the app code 
ADD . $HOME 

# Default command 
CMD ["rails", "server", "--binding", "0.0.0.0”]

Okay...so what’s a “Docker image” for real? 

An image is a read-only template that Docker uses to run your code through a container. It contains a complete environment definition: it has the OS binaries, libraries, dependencies and all the applications that you need to run your code or application. All the magic is stuffed into it, so pay attention! 

Images contain layers (I won’t explain much about them here, since it’s a big topic that requires its own blog post). Every instruction creates a new layer in the filesystem. And thanks to the use of a union filesystem, those layers are “combined” into a single filesystem. Neat and tidy. 

An image can be built and pushed into a registry, like Docker Hub, or Quay.io (or even a custom one), just like you would do with GitHub. You can even have public or private repositories, so others can leverage your image / template, or you can re-use for other purposes.

Digging into your Dockerfile


To help us understand how this all works, let’s examine our freshly baked Rails Dockerfile.

FROM ruby:latest - This is the first instruction you have to have in your Dockerfile, with this instruction we are defining the base image. In our case, it will use this base image https://registry.hub.docker.com/u/library/ruby/, which actually has an interesting hierarchy:

  • Ruby is based on buildpack-deps:jessie which is based on buildpack-deps:jessie-scm which is based on buildpack-deps:jessie-curl, which is finally (!) based on debian:jessie.

  • As you can see, between images there exist some kind of “inheritance” concept where you can “extend” your images from others. It’s a great thing since you can build your environments based on trusted/stable (if you find them! and still be careful) images.

ENV HOME /home/rails/webapp - Just defining an environment variable.
RUN apt-get update -qq && apt-get install -y build-essential nodejs

  • The RUN instruction executes a command in the docker container. So the “apt-get …” command will update the OS packages list and will install some libraries among nodejs.
WORKDIR $HOME - The WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions.
ADD Gemfile* $HOME
/RUN bundle install

  • Copy all the gem files definitions into the filesystem in the container and execute the command to install the gems. (I’ll explain why I’m doing this, in the next “Using Cache in Docker” post :) )

ADD . $HOME - Copy all the website files into the container.

CMD ["rails", "server", "--binding", "0.0.0.0"] - Specify the default command for when the container runs.

Step #3 - Build and Run Your Web App


Now that we have a better idea of our Dockerfile, let’s get our hands dirty! We need to build and run the web app:

$ docker build -t ruby-app .

Since we don’t have a Ruby image downloaded yet, it will pull the latest from Docker Hub and then run all the instructions from the Dockerfile. You should end up with something like this:

Later we can check the image using:

$ docker images

Let’s create a container and run the app.

$ docker run -d -p 3000:3000 rails-app

The command above will create a docker container using the “ruby-app” image you created in Step #2. The “-d” flag tells docker daemon to run this container in “daemon mode”.


Remember our CMD instruction in the Dockerfile? Well that is what’s running in the container “rails server --binding 0.0.0.0”

You can just open your browser at: http://localhost:3000 or you can get the container IP:

docker inspect 8f4fec2497f5 | grep IPAddress

(you can also run docker inspect --format '{{.NetworkSettings.IPAddress}}' 8f4fec2497f5 )

In my case it is: "IPAddress": "172.17.0.2"

So, just open the browser and point it to http://172.17.0.2:3000 and you will see the rails app running :)

One last interesting command about the run command we used is the -p flag.

docker run -d -p 3000:3000 ruby-app

When using the -p flag docker let us choose a port binding between the host and the container. Without this flag we could get into the rails app from outside the container. We could even choose a different port like: 

docker run -d -p 5000:3000 ruby-app

Or let docker choose a random port like
docker run -d -p 3000 ruby-app
To see what port docker has chosen, we can run “docker ps”

Or let docker choose a random port like docker run -d -p 3000 ruby-app To see what port docker has chosen, we can run “docker ps”


And in the port column you will see that the assigned port is 32769.
Also you could do:

$docker port 284bb5e37f44
Result: 3000/tcp -> 0.0.0.0:32769

And in the port column you will see that the assigned port is 32769. Also you could do: $docker port 284bb5e37f44 Result: 3000/tcp -> 0.0.0.0:32769


Using MongoDB With Ruby On Rails 5

In this post I am going to walk you through installing Ruby on Rails 5 using rbenv and use the Mongoid MongoDB driver for Ruby. MongoDB is a fantastic NoSQL database that is incredibly scalable and fast which makes a good combo with Rails. We will be using Linux Ubuntu 16.04 with MongoDB and Rails already installed.

Create a Rails App (Without Active Record)

rails new myapp --skip-active-record
Using the –skip-active-record option will create the app without the database.yml config file. We will use a mongoid config file instead. This will also prevent using the sqlite gem. We will add the Mongoid gem below

Edit Gemfile

Add the following to your Gemfile
gem 'mongoid', '~> 5.1.0'

Generate Mongoid Config File

rails g mongoid:config
This will create config/mongoid.yml
Thats It! you should now be able to run “rails s” and use MongoDB
rails g scaffold post title body author created
Now visit “http://localhost:3000/posts” and you should have CRUD functionality using MongoDB

If you did NOT use the “–skip-active-record”

Remove Gem “sqlite” from the Gemfile
Delete the database.yml file
Go to config/application.rb and remove “require rails/all” and replace with…

require "action_controller/railtie"
require "action_mailer/railtie"
require "rails/test_unit/railtie"
Comment out any line that has “active_record” in it in the following files
/config/development.rb
/config/production.rb
/config/initializers/new_framework_defaults.rb

Sunday, September 18, 2016

Cucumber Interview Questions

Cucumber – a Behavior Driven Development (BDD) framework which is used with Selenium for performing acceptance testing.

Cucumber Introduction:

Cucumber is a tool based on Behavior Driven Development (BDD) framework which is used to write acceptance tests for web application. It allows automation of functional validation in easily readable and understandable format (like plain English) to Business Analysts, Developers, Testers, etc.
Cucumber feature files can serve as a good document for all. There are many other tools like JBehave which also support BDD framework. Initially Cucumber was implemented in Ruby and then extended to Java framework. Both the tools support native JUnit.
Behavior Driven Development is extension of Test Driven Development and it is used to test the system rather than testing the particular piece of code. We will discuss more about the BDD and style of writing BDD tests.
Cucumber can be used along with Selenium, Watir, and Capybara etc. Cucumber supports many other languages like Perl, PHP, Python, .Net etc. In this tutorial we will concentrate on Cucumber with Java as a language.

Cucumber Basics:

In order to understand cucumber we need to know all the features of cucumber and its usage.
#1) Feature Files:
Feature files are essential part of cucumber which is used to write test automation steps or acceptance tests. This can be used as live document. The steps are the application specification. All the feature files ends with .feature extension.
Sample feature file:
Feature: Login Functionality Feature
In order to ensure Login Functionality works,
I want to run the cucumber test to verify it is working
Scenario: Login Functionality
Given user navigates to SOFTWARETETINGHELP.COM
When user logs in using Username as “USER” and Password “PASSWORD”
Then login should be successful
Scenario: Login Functionality
Given user navigates to SOFTWARETETINGHELP.COM
When user logs in using Username as “USER1” and Password “PASSWORD1”
Then error message should be thrown


 ============================================

1) What is Cucumber and what are the advantages of Cucumber?

To run functional tests written in a plain text Cucumber tool is used. It is written in a Ruby programming language.

Advantages of Cucumber

    You can inolve business stakeholders who can not code
    End user experience is priority
    High code reuse

2) What are the 2 files required to execute a Cucumber test scenario?

The 2 files required to execute a Cucumber test scenario are

    Features
    Step Definition

3) What is feature file in Cucumber? What does feature file consist of ?

Feature file in cucumber consist of parameters or conditions required for executing code, they are

    Feature
    Scenario
    Scenario Outline
    Given
    When
    Then

4) Give an example of behaviour driven test in plain text?

    Feature: Visit XYZ page in abc.com
    Scenario : Visit abc.com
    Given:  I am on abc.com
    When:  I click on XYZ page
    Then:  I should see ABC page

5) Explain what is Scenario Outline in feature file?

Scenario Outline:  Same scenario can be executed for multiple sets of data using scenario outline.  The data is provided by a tabular structure separated by (I   I).

6) What is step definition in Cucumber?

A step definition is the actual code implementation of the feature mentioned in feature file.

061114_1018_Introductio1

7) Give the example for step definition using “Given” function?

For example to make visitor visit the site “Yahoo” the command we use for given

Given (/^ I am on www.yahoo.com$/) do

Browser.goto “http://www.yahoo.com”

end – This will visit www.yahoo.com

8) What are the difference between Jbehave and Cucumber?

Although Cucumber and Jbehave are meant for the same purpose, acceptance tests are completely different frameworks

    Jbehave is Java based and Cucumber is Ruby based
    Jbehave are based on stories while Cucumber is based on features

9) Explain what is test harness?

A test harness for cucumber and rspec allows for separating responsibility between setting up the context and interacting with the browser and cleaning up the step definition files

10) Explain when to use Rspec and when to use Cucumber?

    Rspec is used for Unit Testing
    Cucumber is used behaviour driven development. Cucumber can be used for System and Integration Tests

11) What is the language used for expressing scenario in feature file ?

Gherkin language is used to express scenario in feature files and ruby files containing unobtrusive automation for the steps in scenarios

12) Explain what is regular expressions?

A regular expression is a pattern describing a certain amount of text.  The most basic regular expression consists of a single literal character

13) Explain what is BDD (Behaviour Driven Development) ?

BDD or Behaviour driven development is a process of developing software based on TDD (Test Driven Development) which focusses on behavioural specification of software units.

14) What softare do you need to run a Cucumber Web Test ?

    Ruby and its Development Kit
    Cucumber
    IDE like ActiveState
    Watir ( To simulate browser)
    Ansicon and rspec (if required)

15) What does a features/ support file contains?

Features/ support file contains supporting ruby code. Files in support load before those in step_definitions, which can be useful for environment configuration.

Thursday, February 7, 2013

Plugin to upload video to YouTube directly from your site


Source code and sample available at: https://github.com/prabgupt/youtube_video_upload_plugin
Usage: Please note that sample is available for RoR3 but it can be easily converted for any underlying platform. Refer README in git repo above to know how to run it in RoR3. To see how to tweak code to use it for any other platform, keep reading the post.
Purpose of this Utility: It will upload end user’s video directly to youtube and is easily integratable within your website.
Few Advantage:
  • No need to have storage on server machine as you can now dump/use all videos directly to/from youtube.
  • In case you have youtube channel, can directly organize video uploaded through your site to youtube channel.
  • NO need for end user to login to youtube first to upload video through your site.
Flow to upload video on YouTube
  1. Website requests  token and upload URL from youtube for every new video request. This is needed to avoid having end user logging into his/her YouTube account.
  2. Post your video to URL received in step#1 with parameter ‘nexturl’. ‘nexturl’ is callback url to be called by YouTube with status and video_id once upload operation is completed with failure or success. You need to send token received in step#1 too along with.
  3. Youtube invokes ‘nexturl’ with status and video_id, if upload is successful. Process/store this video_id as this will be key from now onwards based on which you can perform operations on this video directly in YouTube.
Source code contains of following things that you need to know:
youtubeUtilAPIs.py- Python script that uses Google Data Python client library.  This script contains few methods performing certain operation on youtube.
Usage: py [-t <comma separated title and description>] [-u <video_id>] [-s <video_id>] [-d <video_id>]
-t => to get token and url. Input required is comma separated video title and video description
-u => to get youtube URL for that video. Input required is video_id
-s => to get upload status of the video. Input required is video_id
-d => to delete video from youtube. Input required is video_id
Prerequisite:
    • Please refer Getting Started guide. In nutshell, you need to install Python and then google Data Library as specified in the link.
    • Replace following senstive data inside python script; like developer key, password, etc. with that of yours. You will need to sign in for YouTube developer key. Once signed in, register you product and get values for below attributes. ‘source’ and ‘client_id’   will be the name of the product you registered before.
yt_service.developer_key = ‘xxxxxxx’
yt_service.client_id = ‘xxxxxxx’
yt_service.email = ‘xxxxxxx’
yt_service.password = ‘xxxxxxxx’
yt_service.source = ‘xxxxxxxxxx’
  • Since above utility contains some sensitive data, hence for security reasons you would need to introduce a server side handler that will execute above script on client request and can send the required details back to client. In our case, we have introduced method ‘uploadToken’ inside multimedia controller which execute python script and returns back token and url needed to upload video on youtube.
1234567891011
def uploadToken
cmd = Rails.root.to_s + '/public/scripts/youtubeUtilAPIs.py'
title = "Test Video"
description = "Test Video description"
resp = `#{cmd} -t "#{title},#{description}"`
resp = resp.split('::')
response = (resp.length == 2) ? {:uploadUrl => resp[0], :token => resp[1]} : ""
respond_to do |format|
format.js {render :js => response.to_json}
end
end
  • Below is the HTML code you’ll plug into your website to let end user select the video and upload it to youtube. Code just contains a form to have end use select the video and has action, token value blank at render time. If you have already noticed, there is async ajax request present at end of code which fetches upload URL and token from server at time page is loading and populate it inside form once ajax request gets completed.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
<div id="upload_video">
<div class="field">
<form action='' id="youtube_video_upload" method="post" enctype="multipart/form-data">
<input name="file" type="file" class="multimedia_file"/>
<div class="errMsg" style="display:none;color:red">
You need to specify a file.
</div>
<div class="errMsg2" style="display:none;color:red">
Video cannot be uploaded this time. Please try again after sometime.
</div>
<input class= "token" name="token" type="hidden" value=""/>
<input value="Upload Video File" class="upload_button" type="submit" />
</form>
</div><br/>
</div>
<script>
$(document).ready(function(){
$(' #youtube_video_upload .multimedia_file').click(function(){
$(this).siblings('.errMsg').css("display", "none");
$(this).children('.errMsg2').css("display", "none");
});
$('#youtube_video_upload').submit(function(){
if ($(this).children('.multimedia_file').val() == null || $(this).children('.multimedia_file').val() == ""){
$(this).children('.errMsg').css("display", "");
return false;
}else if ($(this).children('.token').val() == null || $(this).children('.token').val() == ""){
$(this).children('.errMsg2').css("display", "");
return false;
}
$('#youtube_video_upload').children('.upload_button').attr('disabled', 'true');
});
$('#video_link').click(function(){
$("#add_link").css("display", "none");
$("#upload_video").css("display","");
});
$('#youtube_link').click(function(){
$("#upload_video").css("display","none");
$("#add_link").css("display", "");
$('.errMsg').css("display", "none");
$('.errMsg2').css("display", "none");
});
// asyn ajax request to fetch upload URL and token from youtube
$.get('<%= url_for(:action => "uploadToken", :controller => "multimedias", :only_path => false)%>',function(data){
if(data != ""){
$('#youtube_video_upload').attr('action', data.uploadUrl + '?nexturl=<%= url_for(:action => "new", :controller => "multimedias", :only_path => false)%>');
$('#youtube_video_upload').children('.token').val(data.token);
$('#youtube_video_upload').children('.errMsg2').css("display", "none");
}else{
}
}, "json");
});
</script>

FastAPI: The Modern Python Web Framework

  Introduction to FastAPI: The Modern Python Web Framework The world of web frameworks has always been competitive — from Django and Flask ...