ABSTRACT

SWAT is Simple Web Application Test ( Tool )

SYNOPSIS

SWAT is Simple Web Application Test ( Tool )

$  swat examples/google/ google.ru
/home/vagrant/.swat/reports/google.ru/00.t ..
# start swat for google.ru//
# try num 2
ok 1 - successfull response from GET google.ru/
# data file: /home/vagrant/.swat/reports/google.ru///content.GET.txt
ok 2 - GET / returns 200 OK
ok 3 - GET / returns Google
1..3
ok
All tests successful.
Files=1, Tests=3, 12 wallclock secs ( 0.00 usr  0.00 sys +  0.02 cusr  0.00 csys =  0.02 CPU)
Result: PASS

WHY

I know there are a lot of tests tool and frameworks, but let me briefly tell why I created swat. As devops I update a dozens of web application weekly, sometimes I just have no time sitting and wait while dev guys or QA team ensure that deploy is fine and nothing breaks on the road. So I need a tool to run smoke tests against web applications. Not tool only, but the way to create such a tests from the scratch in way easy and fast enough.

So this how I came up with the idea of swat. If I was a marketing guy I'd say that swat:

Tutorial

Install swat

stable release

sudo cpan install swat

developer release

# developer release might be untested and unstable
sudo cpanm --mirror-only --mirror https://stratopan.com/melezhik/swat-release/master swat

Once swat is installed you have swat command line tool to run swat tests, but before do this you need to create them.

Create tests

mkdir  my-app/ # create a project root directory to contain tests

# define http URIs application should response to

mkdir -p my-app/hello # GET /hello
mkdir -p my-app/hello/world # GET /hello/world

# define the content the expected to return by requested URIs

echo 200 OK >> my-app/hello/get.txt
echo 200 OK >> my-app/hello/world/get.txt

echo 'This is hello' >> my-app/hello/get.txt
echo 'This is hello world' >> my-app/hello/world/get.txt

Run tests

swat ./my-app http://127.0.0.1

DSL

Swat DSL consists of 2 parts. Routes and Swat Data.

Routes

Routes are http resources a tested web application should have.

Swat utilize file system to get know about routes. Let we have a following project layout:

example/my-app/
example/my-app/hello/
example/my-app/hello/get.txt
example/my-app/hello/world/get.txt

When you give swat a run

swat example/my-app 127.0.0.1

It will find all the directories with get.txt|post.txt files inside and "create" routes:

GET hello/
GET hello/world

When you are done with routes you need to set swat data.

Swat data

Swat data is DSL to describe/generate validation checks you apply to content returned from web application. Swat data is stored in swat data files, named get.txt or post.txt.

The process of validation looks like:

Objects found in test data file are called swat entries. There are 3 basic type of swat entries:

Check Expressions

This is most usable type of entries you may define at swat data file. It's just a string should be returned when swat request a given URI. Here are examples:

200 OK
Hello World
<head><title>Hello World</title></head>

Using regexps

Regexps are check expresions with the usage of instead of plain strings checks. Everything started with regexp: marker would be treated as perl regular expression.

# this is example of regexp check
regexp: App Version Number: (\d+\.\d+\.\d+)

Comments

Comments entries are lines started with # symbol, swat will ignore comments when parse swat data file. Here are examples.

# this http status is expected
200 OK
Hello World # this string should be in the response
<head><title>Hello World</title></head> # and it should be proper html code

Perl Expressions

Perl expressions are just a pieces of perl code to get evaled by swat when parsing test data files.

Everything started with code: marker would be treated by swat as perl code to execute. There are a lot of possibilities! Please follow Test::More documentation to get more info about useful function you may call here.

code: skip('next test is skipped',1) # skip next check forever
HELLO WORLD


code: skip('next test is skipped',1) unless $ENV{'debug'} == 1  # confitionally skip this check
HELLO SWAT

Generators

Swat entries generators is the way to create new swat entries on the fly. Technically specaking it's just a perl code which should return an array reference: Generators are very close to perl expressions ( generators code is alos get evaled ) with maijor difference:

Value returned from generator's code should be array reference. The array is passed back to swat parser so it can create new swat entries from it.

Generators entries start with :generator marker. Here is example:

# Place this in swat pattern file
generator: [ qw{ foo bar baz } ]

This generator will generate 3 swat entries:

foo
bar
baz

As you can guess an array returned by generator should contain perl strings representing swat entries, here is another example: with generator producing still 3 swat entites 'foo', 'bar', 'baz' :

# Place this in swat pattern file
generator: my %d = { 'foo' => 'foo value', 'bar' => 'bar value' }; [ map  { ( "# $_", "$data{$_}" )  } keys %d  ] 

This generator will generate 3 swat entities:

# foo
foo value
# bar
bar value

There is no limit for you! Use any code you want with only requiment - it should return array reference. What about to validate web application content with sqlite database entries?

# Place this in swat pattern file
generator:                                                          \

use DBI;                                                            \
my $dbh = DBI->connect("dbi:SQLite:dbname=t/data/test.db","","");   \
my $sth = $dbh->prepare("SELECT name from users");                  \
$sth->execute();                                                    \
my $results = $sth->fetchall_arrayref;                              \

[ map { $_->[0] } @${results} ]

See examples/swat-generators-sqlite3 for working example

Multiline expressions

Sometimes code looks more readable when you split it on separate chunks. When swat parser meets \ symbols it postpone entry execution and add next line to buffer. This is repeated till no \ found on next. Finally swat execute "accumulated" swat entity.

Here are some exmaples:

# Place this in swat pattern file
generator:                  \
my %d = {                   \
    'foo' => 'foo value',   \
    'bar' => 'bar value',   \
    'baz' => 'baz value'    \
};                          \
[                                               \
    map  { ( "# $_", "$data{$_}" )  } keys %d   \
]                                               \

# Place this in swat pattern file
generator: [            \
        map {           \
        uc($_)          \
    } qw( foo bar baz ) \
]

code:                                                       \
if $ENV{'debug'} == 1  { # confitionally skip this check    \
    skip('next test is skipped',1)                          \ 
} 
HELLO SWAT

Multiline expressions are only allowable for perl expressions and generators

Post requests

Name swat data file as post.txt to make http POST requests.

echo 200 OK >> my-app/hello/post.txt
echo 200 OK >> my-app/hello/world/post.txt

You may use curl_params setting ( follow "Swat Settings" section for details ) to define post data, there are some examples:

Generators and Perl Expressions Scope

Swat uses perl string eval when process generators and perl expressions code, be aware of this. Follow http://perldoc.perl.org/functions/eval.html to get more on this.

Swat Settings

Swat comes with settings defined in two contexts:

Environmental Variables

Defining a proper environment variables will provide swat settings.

Swat.ini files

Swat checks files named swat.ini in the following directories

Here are examples of locations of swat.ini files:

 ~/swat.ini # home directory swat.ini file
 my-app/swat.ini # project_root directory swat.ini file
 my-app/hello/get.txt
 my-app/hello/swat.ini # route directory swat.ini file ( route hello )
 my-app/hello/world/get.txt
 my-app/hello/world/swat.ini # route directory swat.ini file ( route hello/world )

Once file exists at any location swat simply bash sources it to apply settings.

Thus swat.ini file should be bash file with swat variables definitions. Here is example:

# the content of swat.ini file:
curl_params="-H 'Content-Type: text/html'"
debug=1

Settings priority table

Here is the list of settings/contexts in priority ascending order:

| context                 | location                | priority  level |
| ------------------------|------------------------ | --------------- |
| swat.ini file           | ~/swat.ini              |               1 |
| environmental variables | ---                     |               2 |
| swat.ini file           | project root directory  |               3 |
| swat.ini file           | route directory         |               4 |

Swat processes settings in order. For every route found swat:

TAP

Swat produce output in TAP format , that means you may use your favorite tap parsers to bring result to another test / reporting systems, follow TAP documentation to get more on this. Here is example for converting swat tests into JUNIT format

swat $project_root $host --formatter TAP::Formatter::JUnit

See also "Prove settings" section.

Command line tool

Swat is shipped as cpan package, once it's installed ( see "Install swat" section ) you have a command line tool called swat, this is usage info on it:

swat project_dir URL <prove settings>

Prove settings

Swat utilize prove utility to run tests, so all the swat options are passed as is to prove utility. Follow prove utility documentation for variety of values you may set here. Default value for prove options is -v. Here is another examples:

Debuggins

set swat_debug environmental variable to 1

Examples

./examples directory contains examples of swat tests for different cases. Follow README.md files for details.

Dependencies

Not that many :)

AUTHOR

Aleksei Melezhik

Thanks

To the authors of ( see list ) without who swat would not appear to light