package Rex::Test::Spec;
use 5.006;
use strict;
use warnings FATAL => 'all';
my @EXPORT = qw(describe context its it);
my @testFuncs = qw(ok is isnt like unlike is_deeply);
my @typeFuncs = qw(cron file gateway group iptables
pkg port process routes run service sysctl user);
push @EXPORT, @testFuncs, @typeFuncs, 'done_testing';
our ($obj, $msg);
use Test::More;
=head1 NAME
Rex::Test::Spec - Write Rex::Test like RSpec!
=head1 VERSION
Version 0.08
=cut
our $VERSION = '0.08';
=head1 SYNOPSIS
use Rex::Test::Spec;
describe "Nginx Test", sub {
context run("nginx -t"), "nginx.conf testing", sub {
like its('stdout'), qr/ok/;
};
context file("~/.ssh/id_rsa"), sub {
is its('ensure'), 'file';
is its('mode'), '0600';
like its('content'), qr/name\@email\.com/;
};
context file("/data"), sub {
is its('ensure'), 'directory';
is its('owner'), 'www';
is its('mounted_on'), '/dev/sdb1';
isnt its('writable');
};
context service("nginx"), sub {
is its('ensure'), 'running';
};
context pkg("nginx"), sub {
is its('ensure'), 'present';
is its('version'), '1.5.8';
};
context cron, sub {
like its('www'), 'logrotate';
};
context gateway, sub {
is it, '192.168.0.1';
};
context group('www'), sub {
ok its('ensure');
};
context iptables, sub {
};
context port(80), sub {
is its('bind'), '0.0.0.0';
is its('proto'), 'tcp';
is its('command'), 'nginx';
};
context process('nginx'), sub {
like its('command'), qr(nginx -c /etc/nginx.conf);
ok its('mem') > 1024;
};
context routes, sub {
is_deeply its(1), {
destination => $dest,
gateway => $gw,
genmask => $genmask,
flags => $flags,
mss => $mss,
irtt => $irtt,
iface => $iface,
};
};
context sysctl, sub {
is its('vm.swapiness'), 1;
};
context user('www'), sub {
ok its('ensure');
is its('home'), '/var/www/html';
is its('shell'), '/sbin/nologin';
is_deeply its('belong_to'), ['www', 'nogroup'];
};
};
done_testing;
=head1 EXPORT FUNCTIONS
=head2 Spec definition functions
These are the functions you will use to define behaviors and run your specs:
I<describe> (and alias to I<context>), I<its> (alias to I<it>).
Normally suggest C<< describe "strings" >> and C<< context resource type object >>,
use C<< its(key) >> return value, C<< it >> return objects by default.
=cut
sub describe {
my $code = pop;
local $msg = '';
local $obj;
if ( defined $_[0] and ref($_[0]) =~ m/^Rex::Test::Spec::(\w+)$/ ) {
$msg .= sprintf "%s(%s)", $1, $_[0]->{name};
$obj = shift;
};
$msg .= join(' ', @_) if scalar @_;
$code->();
}
BEGIN { *context = \&describe }
sub its {
return $obj->getvalue(@_);
}
BEGIN { *it = \&its }
=head2 Test::More export functions
This now include I<is>, I<isnt>, I<ok>, I<is_deeply>, I<like>, I<unlike>, I<done_testing>.
You'll use these to assert correct behavior.
The resource type name will be automatic passed as testing message.
=cut
for my $func (@testFuncs) {
no strict 'refs';
no warnings;
*$func = sub {
Test::More->can($func)->(@_, $msg);
};
};
BEGIN { *done_testing = \&Test::More::done_testing }
=head2 Rex resource type generation functions
Now support I<cron>, I<gateway>, I<iptables>, I<port>, I<routes>, I<service>,
I<user>, I<file>, I<group>, I<pkg>, I<process>, I<run>, I<sysctl>.
See L</"SYNOPSIS"> for more details.
=cut
sub AUTOLOAD {
my ($method) = our $AUTOLOAD =~ /^[\w:]+::(\w+)$/;
return if $method eq 'DESTROY';
eval "use $AUTOLOAD";
die "Error loading $AUTOLOAD." if $@;
my @args = @_;
unshift @args, 'name' if scalar @args == 1;
return $AUTOLOAD->new(@args);
}
sub import {
no strict 'refs';
no warnings;
for ( @EXPORT ) {
*{"main::$_"} = \&$_;
}
}
=head1 AUTHOR
Rao Chenlin(chenryn), C<< <rao.chenlin at gmail.com> >>
=head1 SEE ALSO
=over 4
=item 1. Rspec
L<http://rspec.info/>
=item 2. Serverspec
L<http://serverspec.org/>
=item 3. TDD (Test Driven Development)
L<http://en.wikipedia.org/wiki/Test-driven_development>
=item 4. BDD (Behavior Driven Development)
L<http://en.wikipedia.org/wiki/Behavior_Driven_Development>
=item 5. L<Test::More>
=item 6. L<Rex>
=back
=head1 BUGS
Please report any bugs or feature requests to C<bug-rex-test-spec at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Rex-Test-Spec>. I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.
Also accept pull requests and issue at L<https://github.com/chenryn/Rex--Test--Spec>.
=head1 LICENSE AND COPYRIGHT
Copyright 2014 Rao Chenlin(chenryn).
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
L<http://www.apache.org/licenses/LICENSE-2.0/>
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=cut
1; # End of Rex::Test::Spec