SlideShare una empresa de Scribd logo
1 de 213
Descargar para leer sin conexión
21st Century
CPAN Testing
Mike Friedman
(friedo)
MongoDB, Inc.
Aug. 27, 2013:
, Inc.
, Inc.
makes
(the database)
, Inc.
makes
(the database)
employs
Mike Friedman
(friedo)
, Inc.
makes
(the database)
employs
Mike Friedman
(friedo)
WAT
What is
MongoDB?
Open
Source
Non-relational
Horizontally
Scalable
Document-
oriented
Fast Database
Fault-tolerant CoolSchemaless
Document-
oriented
Document-
oriented
JSON-like thingy:
{
"foo": "a string",
"bar": 42,
"baz": [ 1, 2, "narf", "poit" ],
"quux": {
"key_1": "w00t.",
"key_2": "you get the idea",
}
}
{
"foo": "a string",
"bar": 42,
"baz": [ 1, 2, "narf", "poit" ],
"quux": {
"key_1": "w00t.",
"key_2": "you get the idea",
}
}
{
"foo": "a string",
"bar": 42,
"baz": [ 1, 2, "narf", "poit" ],
"quux": {
"key_1": "w00t.",
"key_2": "you get the idea",
}
}
{
"foo": "a string",
"bar": 42,
"baz": [ 1, 2, "narf", "poit" ],
"quux": {
"key_1": "w00t.",
"key_2": "you get the idea",
}
}
First-Class Objects
First-Class Objects
First-Class Objects
First-Class Objects
Queryable
First-Class Objects
Queryable Indexable
First-Class Objects
Queryable Indexable Updateable
Testing CPAN
in the
21st Century
A lengthy series of bad
ideas and stupid
questions.
Stupid Question No. 1
Stupid Question No. 1
Who here uses CPAN?
Stupid Question No. 2
Stupid Question No. 2
Who here is a CPAN author?
What’s this about,
anyway?
What’s this about,
anyway?
CPANci
A Brief History
A Brief History
•December 18, 1987
A Brief History
•December 18, 1987
•Perl 1.000 released.
A Brief History
•December 18, 1987
•Perl 1.000 released.
•TAP invented.
The Test Anything Protocol
The Test Anything Protocol
1..42
ok 1 the thing looks good!
ok 2
ok 3 $beer isa $drink
not ok 4 too much $beer
not ok 5 $me->vomit( 'now' )
...
A Brief History
A Brief History
•October 17, 1994
A Brief History
•October 17, 1994
•Perl 5.000 released.
A Brief History
•October 17, 1994
•Perl 5.000 released.
•Perl has a module system.
# from this
require "funcs.pl";
# from this
require "funcs.pl";
# to this
use My::Module;
# but under the hood
BEGIN {
require My::Module;
My::Module->import;
};
A Brief History
A Brief History
•October 26, 1995
A Brief History
•October 26, 1995
•CPAN established.
A Brief History
•October 26, 1995
•CPAN established.
•Perl modules are available.
A Brief History
A Brief History
•May 15, 1997
A Brief History
•May 15, 1997
•Perl 5.004 released.
A Brief History
•May 15, 1997
•Perl 5.004 released.
•CPAN.pm is in the core.
# the dark art
$ perl -MCPAN -e 'install Foo'
A Brief History
A Brief History
•May, 1998
A Brief History
•May, 1998
•CPAN Testers conceived
A Brief History
•May, 1998
•CPAN Testers conceived
•Automated feedback for authors
A Brief History
A Brief History
•November 15, 2003
A Brief History
•November 15, 2003
•Perl 5.6.2 released.
A Brief History
•November 15, 2003
•Perl 5.6.2 released.
•Test::More is in the core.
use Test::More tests => 3;
ok( 42 );
is( $foo, 'my value' );
isnt( 'foo', 'bar' );
A Brief History
A Brief History
•August 6, 2012
A Brief History
•August 6, 2012
•Mike goes to work for 10gen
A Brief History
•August 6, 2012
•Mike goes to work for 10gen MongoDB
Bad Idea No. 1
Bad Idea No. 1
Come up with a cool Perl MongoDB project
to show off atYAPC!
Bad Idea No. 1
Come up with a cool Perl MongoDB project
to show off atYAPC!
It'll be fun!
Bad Idea No. 1
Come up with a cool Perl MongoDB project
to show off atYAPC!
It'll be fun!
promise!
CPAN Testers
CPAN Testers is Wonderful and
Amazing
Disadvantages:
Disadvantages:
Not real time
Disadvantages:
Not real time
Not consistent
Disadvantages:
Not real time
Not consistent
Polluted / Inconsistent
environments
Disadvantages:
Not real time
Not consistent
Polluted / Inconsistent
environments
Not all versions on all platforms
Perl 5.18 runs on
GNU Hurd
Perl 5.18 runs on
GNU Hurd
?
Perl 5.18 runs on
GNU Hurd
?
Perl 5.18 runs on
GNU Hurd
?
I
♥
CPAN
I don't care.
I care about:
I care about:
I care about:
I care about:
I want Continuous Integration
for the entire CPAN.
I want Continuous Integration
for the entire CPAN.
For platforms I care about.
Bad Idea No. 2
CPANci.org
Bad Idea No. 2
Stupid Question No. 3
Stupid Question No. 3
How can we test CPAN without the
disadvantages of CPAN Testers?
Postulate:
Every CPAN distribution must be tested in isolation, on a
virgin Perl installation untouched by human hands.
I release distribution Foo-Awesome-0.0000001
I release distribution Foo-Awesome-0.0000001
use Spiffy::Module;
I release distribution Foo-Awesome-0.0000001
use Spiffy::Module;
Forgotten dependency!
I release distribution Foo-Awesome-0.0000001
use Spiffy::Module;
Forgotten dependency!
What happens?
Scenario  I
The  tester  hath  not  the  missing  
dependency  upon  his  box.
FAIL-
mail
Scenario  II
The  tester  doth  possess  
the  dependency  upon  his  box.
EVERYTHING
IS FINE.
NOT FINE.
Postulate:
Every CPAN distribution must be tested in isolation, on a
virgin Perl installation untouched by human hands.
Postulate:
Every CPAN distribution must be tested in isolation, on a
virgin Perl installation untouched by human hands.
So how do we do that?
perlbrew
Virtualization
Virtualization
Whoa!
Bad Idea No. 3
•Create an EC2 image
•Create an EC2 image
•Put perlbrew on it
•Create an EC2 image
•Put perlbrew on it
•Install every Perl locally
•Create an EC2 image
•Put perlbrew on it
•Install every Perl locally
•Boot an instance for every
uploaded distribution
•Create an EC2 image
•Put perlbrew on it
•Install every Perl locally
•Boot an instance for every
uploaded distribution
•Install needed dependencies
for the distribution
•Create an EC2 image
•Put perlbrew on it
•Install every Perl locally
•Boot an instance for every
uploaded distribution
•Install needed dependencies
for the distribution
•Run the tests and report the
results
•Create an EC2 image
•Put perlbrew on it
•Install every Perl locally
•Boot an instance for every
uploaded distribution
•Install needed dependencies
for the distribution
•Run the tests and report the
results
•Shut down the instance
Uh-oh.
Stupid Question No. 4
Stupid Question No. 4
How can we do this on one instance?
local::lib
cpanminus
App::cpanminus
App::cpanminus
•Self-contained
App::cpanminus
•Self-contained
•That is, the cpanm script is self-contained
App::cpanminus
•Self-contained
•That is, the cpanm script is self-contained
•via App::FatPacker
App::cpanminus
App::cpanminus
That means the same cpanm can be run by any perl
App::cpanminus
That means the same cpanm can be run by any perl
perlbrew switch master
curl -L http://cpanmin.us/ | perl - App::cpanminus
ln -s ~/perl5/perlbrew/perls/master/bin/cpanm ./cpanm
~/perl5/perlbrew/perls/perl-5.8.9/bin/perl cpanm
~/perl5/perlbrew/perls/perl-5.10.1/bin/perl cpanm
~/perl5/perlbrew/perls/perl-5.12.5/bin/perl cpanm
~/perl5/perlbrew/perls/perl-5.14.4/bin/perl cpanm
~/perl5/perlbrew/perls/perl-5.16.3/bin/perl cpanm
~/perl5/perlbrew/perls/perl-5.18.0/bin/perl cpanm
~/perl5/perlbrew/perls/perl-5.19.0/bin/perl cpanm
•Use perlbrew to install a "master" perl
•Use perlbrew to install a "master" perl
•Use it again to install "virgin" perls of every
major version
•Use perlbrew to install a "master" perl
•Use it again to install "virgin" perls of every
major version
•Use the master perl to install everything
from CPAN that makes CPANci work
•Use perlbrew to install a "master" perl
•Use it again to install "virgin" perls of every
major version
•Use the master perl to install everything
from CPAN that makes CPANci work
•For each distribution, create a temp
directory
•Use perlbrew to install a "master" perl
•Use it again to install "virgin" perls of every
major version
•Use the master perl to install everything
from CPAN that makes CPANci work
•For each distribution, create a temp
directory
•Tell cpanminus to install dependencies
there, as if for local::lib
•Use perlbrew to install a "master" perl
•Use it again to install "virgin" perls of every
major version
•Use the master perl to install everything
from CPAN that makes CPANci work
•For each distribution, create a temp
directory
•Tell cpanminus to install dependencies
there, as if for local::lib
•Run tests and report results
•Use perlbrew to install a "master" perl
•Use it again to install "virgin" perls of every
major version
•Use the master perl to install everything
from CPAN that makes CPANci work
•For each distribution, create a temp
directory
•Tell cpanminus to install dependencies
there, as if for local::lib
•Run tests and report results
•Delete temp directory, leaving each perl
untouched!
What does that look like?
The "fetcher" grabs the latest distribution URLs from
MetaCPAN's RSS feed.
my $xml = XML::LibXML->load_xml(
string => $self->ua->get( $self->rss_base )->decoded_content
);
my @dists = map {
my $u = URI->new( $_->getAttribute( 'rdf:resource' ) );
$u->host( 'api.metacpan.org' );
$u->path( 'v0' . $u->path );
$u;
} $xml->findnodes( '//rdf:li' );
What does that look like?
The "fetcher" grabs the latest distribution URLs from
MetaCPAN's RSS feed.
my $xml = XML::LibXML->load_xml(
string => $self->ua->get( $self->rss_base )->decoded_content
);
my @dists = map {
my $u = URI->new( $_->getAttribute( 'rdf:resource' ) );
$u->host( 'api.metacpan.org' );
$u->path( 'v0' . $u->path );
$u;
} $xml->findnodes( '//rdf:li' );
What does that look like?
The "fetcher" grabs the latest distribution URLs from
MetaCPAN's RSS feed.
my $xml = XML::LibXML->load_xml(
string => $self->ua->get( $self->rss_base )->decoded_content
);
my @dists = map {
my $u = URI->new( $_->getAttribute( 'rdf:resource' ) );
$u->host( 'api.metacpan.org' );
$u->path( 'v0' . $u->path );
$u;
} $xml->findnodes( '//rdf:li' );
What does that look like?
The "fetcher" grabs the latest distribution URLs from
MetaCPAN's RSS feed.
my $xml = XML::LibXML->load_xml(
string => $self->ua->get( $self->rss_base )->decoded_content
);
my @dists = map {
my $u = URI->new( $_->getAttribute( 'rdf:resource' ) );
$u->host( 'api.metacpan.org' );
$u->path( 'v0' . $u->path );
$u;
} $xml->findnodes( '//rdf:li' );
What does that look like?
We retrieve the distribution metadata from
the MetaCPAN JSON API and save it to
MongoDB.
foreach my $dist( @dists ) {
my $fetched_data = decode_json
$self->ua->get( $dist )->decoded_content;
my %ins = ( _id => 'cpan/' . $name,
fetched => DateTime->now,
meta => $fetched_data );
$coll->insert( %ins );
}
What does that look like?
We retrieve the distribution metadata from
the MetaCPAN JSON API and save it to
MongoDB.
foreach my $dist( @dists ) {
my $fetched_data = decode_json
$self->ua->get( $dist )->decoded_content;
my %ins = ( _id => 'cpan/' . $name,
fetched => DateTime->now,
meta => $fetched_data );
$coll->insert( %ins );
}
What does that look like?
We retrieve the distribution metadata from
the MetaCPAN JSON API and save it to
MongoDB.
foreach my $dist( @dists ) {
my $fetched_data = decode_json
$self->ua->get( $dist )->decoded_content;
my %ins = ( _id => 'cpan/' . $name,
fetched => DateTime->now,
meta => $fetched_data );
$coll->insert( %ins );
}
What does that look like?
We retrieve the distribution metadata from
the MetaCPAN JSON API and save it to
MongoDB.
foreach my $dist( @dists ) {
my $fetched_data = decode_json
$self->ua->get( $dist )->decoded_content;
my %ins = ( _id => 'cpan/' . $name,
fetched => DateTime->now,
meta => $fetched_data );
$coll->insert( %ins );
}
What does that look like?
We retrieve the distribution metadata from
the MetaCPAN JSON API and save it to
MongoDB.
foreach my $dist( @dists ) {
my $fetched_data = decode_json
$self->ua->get( $dist )->decoded_content;
my %ins = ( _id => 'cpan/' . $name,
fetched => DateTime->now,
meta => $fetched_data );
$coll->insert( %ins );
}
What does that look like?
We extract the archive in a specific "work" directory
for each perl.
Then use a temp directory for building and installing
dependencies.
foreach my $perl ( @{ $self->perls } ) {
my $workdir = catdir $self->home, 'work', $perl, $dist;
chdir $workdir;
}
What does that look like?
We extract the archive in a specific "work" directory
for each perl.
Then use a temp directory for building and installing
dependencies.
foreach my $perl ( @{ $self->perls } ) {
my $workdir = catdir $self->home, 'work', $perl, $dist;
chdir $workdir;
}
What does that look like?
We extract the archive in a specific "work" directory
for each perl.
Then use a temp directory for building and installing
dependencies.
foreach my $perl ( @{ $self->perls } ) {
my $workdir = catdir $self->home, 'work', $perl, $dist;
chdir $workdir;
}
What does that look like?
We extract the archive in a specific "work" directory
for each perl.
Then use a temp directory for building and installing
dependencies.
foreach my $perl ( @{ $self->perls } ) {
my $workdir = catdir $self->home, 'work', $perl, $dist;
chdir $workdir;
}
What does that look like?
Use a specific perl binary to run cpanm and
install dependencies, with no tests, to the temp
directory.
Then we parse the cpanm log on stderr
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $pid = open3 $wtr, $rdr, $err, $plbin, $self->cpanm,
'--installdeps', '--notest', '-L', $dist_tmp, '.';
my $results = $self->_read_cpanm_deps_log( $err );
What does that look like?
Use a specific perl binary to run cpanm and
install dependencies, with no tests, to the temp
directory.
Then we parse the cpanm log on stderr
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $pid = open3 $wtr, $rdr, $err, $plbin, $self->cpanm,
'--installdeps', '--notest', '-L', $dist_tmp, '.';
my $results = $self->_read_cpanm_deps_log( $err );
What does that look like?
Use a specific perl binary to run cpanm and
install dependencies, with no tests, to the temp
directory.
Then we parse the cpanm log on stderr
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $pid = open3 $wtr, $rdr, $err, $plbin, $self->cpanm,
'--installdeps', '--notest', '-L', $dist_tmp, '.';
my $results = $self->_read_cpanm_deps_log( $err );
What does that look like?
Use a specific perl binary to run cpanm and
install dependencies, with no tests, to the temp
directory.
Then we parse the cpanm log on stderr
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $pid = open3 $wtr, $rdr, $err, $plbin, $self->cpanm,
'--installdeps', '--notest', '-L', $dist_tmp, '.';
my $results = $self->_read_cpanm_deps_log( $err );
What does that look like?
Use a specific perl binary to run cpanm and
install dependencies, with no tests, to the temp
directory.
Then we parse the cpanm log on stderr
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $pid = open3 $wtr, $rdr, $err, $plbin, $self->cpanm,
'--installdeps', '--notest', '-L', $dist_tmp, '.';
my $results = $self->_read_cpanm_deps_log( $err );
What does that look like?
Use a specific perl binary to run cpanm and
install dependencies, with no tests, to the temp
directory.
Then we parse the cpanm log on stderr
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $pid = open3 $wtr, $rdr, $err, $plbin, $self->cpanm,
'--installdeps', '--notest', '-L', $dist_tmp, '.';
my $results = $self->_read_cpanm_deps_log( $err );
"deps" : {
	 	 "log" : [
	 	 	 {
	 	 	 	 "indent" : 0,
	 	 	 	 "type" : "working-on",
	 	 	 	 "line" : "--> Working on .n"
	 	 	 },
	 	 	 {
	 	 	 	 "line" : "Configuring Lingua-EN-NamedEntity-1.92 ... OKn",
	 	 	 	 "type" : "config",
	 	 	 	 "indent" : 1
	 	 	 },
	 	 	 {
	 	 	 	 "type" : "found-deps",
	 	 	 	 "indent" : 1,
	 	 	 	 "line" : "==> Found dependencies: Lingua::Stem::En, DB_File, LWP::Simplen"
	 	 	 },
	 	 	 {
	 	 	 	 "indent" : 1,
	 	 	 	 "type" : "working-on",
	 	 	 	 "line" : "--> Working on Lingua::Stem::Enn"
	 	 	 },
	 	 	 {
	 	 	 	 "indent" : 2,
	 	 	 	 "type" : "fetch",
	 	 	 	 "line" : "Fetching http://www.cpan.org/authors/id/S/SN/SNOWHARE/Lingua-
Stem-0.84.tar.gz ... OKn"
	 	 	 },
What does that look like?
What does that look like?
Use a specific perl to run each test file,
save the TAP output and any errors, and
use the exit status to determine if it passed.
foreach my $test( @tests ) {
my @test_results;
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $idir = catdir $dist_tmp, 'lib', 'perl5';
my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test;
my ( $tap_out, $errors );
{ local $/;
$tap_out = readline $rdr; $errors = readline $err;
}
waitpid $pid, 0;
my $passed = ( ( $? >> 8 ) == 0 ) true : false );
}
What does that look like?
Use a specific perl to run each test file,
save the TAP output and any errors, and
use the exit status to determine if it passed.
foreach my $test( @tests ) {
my @test_results;
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $idir = catdir $dist_tmp, 'lib', 'perl5';
my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test;
my ( $tap_out, $errors );
{ local $/;
$tap_out = readline $rdr; $errors = readline $err;
}
waitpid $pid, 0;
my $passed = ( ( $? >> 8 ) == 0 ) true : false );
}
What does that look like?
Use a specific perl to run each test file,
save the TAP output and any errors, and
use the exit status to determine if it passed.
foreach my $test( @tests ) {
my @test_results;
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $idir = catdir $dist_tmp, 'lib', 'perl5';
my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test;
my ( $tap_out, $errors );
{ local $/;
$tap_out = readline $rdr; $errors = readline $err;
}
waitpid $pid, 0;
my $passed = ( ( $? >> 8 ) == 0 ) true : false );
}
What does that look like?
Use a specific perl to run each test file,
save the TAP output and any errors, and
use the exit status to determine if it passed.
foreach my $test( @tests ) {
my @test_results;
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $idir = catdir $dist_tmp, 'lib', 'perl5';
my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test;
my ( $tap_out, $errors );
{ local $/;
$tap_out = readline $rdr; $errors = readline $err;
}
waitpid $pid, 0;
my $passed = ( ( $? >> 8 ) == 0 ) true : false );
}
What does that look like?
Use a specific perl to run each test file,
save the TAP output and any errors, and
use the exit status to determine if it passed.
foreach my $test( @tests ) {
my @test_results;
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $idir = catdir $dist_tmp, 'lib', 'perl5';
my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test;
my ( $tap_out, $errors );
{ local $/;
$tap_out = readline $rdr; $errors = readline $err;
}
waitpid $pid, 0;
my $passed = ( ( $? >> 8 ) == 0 ) true : false );
}
What does that look like?
Use a specific perl to run each test file,
save the TAP output and any errors, and
use the exit status to determine if it passed.
foreach my $test( @tests ) {
my @test_results;
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $idir = catdir $dist_tmp, 'lib', 'perl5';
my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test;
my ( $tap_out, $errors );
{ local $/;
$tap_out = readline $rdr; $errors = readline $err;
}
waitpid $pid, 0;
my $passed = ( ( $? >> 8 ) == 0 ) true : false );
}
What does that look like?
Use a specific perl to run each test file,
save the TAP output and any errors, and
use the exit status to determine if it passed.
foreach my $test( @tests ) {
my @test_results;
my $plbin = catfile $self->pldir, $perl, 'bin', 'perl';
my $idir = catdir $dist_tmp, 'lib', 'perl5';
my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test;
my ( $tap_out, $errors );
{ local $/;
$tap_out = readline $rdr; $errors = readline $err;
}
waitpid $pid, 0;
my $passed = ( ( $? >> 8 ) == 0 ) true : false );
}
What does that look like?
Parse the TAP output of each test into a
structure which can be saved in MongoDB
eval {
my $parser = TAP::Parser->new( { source => $tap_out } );
while( my $result = $parser->next ) {
push @test_results,
{ text => $result->as_string,
ok => ( $result_is_ok ? true : false ),
type => $result->type,
$result->type eq 'test' ?
( number => $result->number,
desc => ( $result->description =~ s/^- //r )
) : ( ),
};
}
};
What does that look like?
Parse the TAP output of each test into a
structure which can be saved in MongoDB
eval {
my $parser = TAP::Parser->new( { source => $tap_out } );
while( my $result = $parser->next ) {
push @test_results,
{ text => $result->as_string,
ok => ( $result_is_ok ? true : false ),
type => $result->type,
$result->type eq 'test' ?
( number => $result->number,
desc => ( $result->description =~ s/^- //r )
) : ( ),
};
}
};
What does that look like?
Parse the TAP output of each test into a
structure which can be saved in MongoDB
eval {
my $parser = TAP::Parser->new( { source => $tap_out } );
while( my $result = $parser->next ) {
push @test_results,
{ text => $result->as_string,
ok => ( $result_is_ok ? true : false ),
type => $result->type,
$result->type eq 'test' ?
( number => $result->number,
desc => ( $result->description =~ s/^- //r )
) : ( ),
};
}
};
What does that look like?
Parse the TAP output of each test into a
structure which can be saved in MongoDB
eval {
my $parser = TAP::Parser->new( { source => $tap_out } );
while( my $result = $parser->next ) {
push @test_results,
{ text => $result->as_string,
ok => ( $result_is_ok ? true : false ),
type => $result->type,
$result->type eq 'test' ?
( number => $result->number,
desc => ( $result->description =~ s/^- //r )
) : ( ),
};
}
};
What does that look like?
Parse the TAP output of each test into a
structure which can be saved in MongoDB
eval {
my $parser = TAP::Parser->new( { source => $tap_out } );
while( my $result = $parser->next ) {
push @test_results,
{ text => $result->as_string,
ok => ( $result_is_ok ? true : false ),
type => $result->type,
$result->type eq 'test' ?
( number => $result->number,
desc => ( $result->description =~ s/^- //r )
) : ( ),
};
}
};
What does that look like?
Parse the TAP output of each test into a
structure which can be saved in MongoDB
eval {
my $parser = TAP::Parser->new( { source => $tap_out } );
while( my $result = $parser->next ) {
push @test_results,
{ text => $result->as_string,
ok => ( $result_is_ok ? true : false ),
type => $result->type,
$result->type eq 'test' ?
( number => $result->number,
desc => ( $result->description =~ s/^- //r )
) : ( ),
};
}
};
What does that look like?
Parse the TAP output of each test into a
structure which can be saved in MongoDB
eval {
my $parser = TAP::Parser->new( { source => $tap_out } );
while( my $result = $parser->next ) {
push @test_results,
{ text => $result->as_string,
ok => ( $result_is_ok ? true : false ),
type => $result->type,
$result->type eq 'test' ?
( number => $result->number,
desc => ( $result->description =~ s/^- //r )
) : ( ),
};
}
};
What does that look like?
Parse the TAP output of each test into a
structure which can be saved in MongoDB
eval {
my $parser = TAP::Parser->new( { source => $tap_out } );
while( my $result = $parser->next ) {
push @test_results,
{ text => $result->as_string,
ok => ( $result_is_ok ? true : false ),
type => $result->type,
$result->type eq 'test' ?
( number => $result->number,
desc => ( $result->description =~ s/^- //r )
) : ( ),
};
}
};
What does that look like?
Parse the TAP output of each test into a
structure which can be saved in MongoDB
eval {
my $parser = TAP::Parser->new( { source => $tap_out } );
while( my $result = $parser->next ) {
push @test_results,
{ text => $result->as_string,
ok => ( $result_is_ok ? true : false ),
type => $result->type,
$result->type eq 'test' ?
( number => $result->number,
desc => ( $result->description =~ s/^- //r )
) : ( ),
};
}
};
What does that look like?
Parse the TAP output of each test into a
structure which can be saved in MongoDB
eval {
my $parser = TAP::Parser->new( { source => $tap_out } );
while( my $result = $parser->next ) {
push @test_results,
{ text => $result->as_string,
ok => ( $result_is_ok ? true : false ),
type => $result->type,
$result->type eq 'test' ?
( number => $result->number,
desc => ( $result->description =~ s/^- //r )
) : ( ),
};
}
};
What does that look like?
Parse the TAP output of each test into a
structure which can be saved in MongoDB
eval {
my $parser = TAP::Parser->new( { source => $tap_out } );
while( my $result = $parser->next ) {
push @test_results,
{ text => $result->as_string,
ok => ( $result_is_ok ? true : false ),
type => $result->type,
$result->type eq 'test' ?
( number => $result->number,
desc => ( $result->description =~ s/^- //r )
) : ( ),
};
}
};
What does that look like?
What does that look like?
	

 {
	

 	

 "number" : 6,
	

 	

 "ok" : true,
	

 	

 "type" : "test",
	

 	

 "desc" : "depth",
	

 	

 "text" : "ok 6 - depth"
	

 },
What does that look like?
	

 {
	

 	

 "number" : 6,
	

 	

 "ok" : true,
	

 	

 "type" : "test",
	

 	

 "desc" : "depth",
	

 	

 "text" : "ok 6 - depth"
	

 },
•This is JSON
What does that look like?
	

 {
	

 	

 "number" : 6,
	

 	

 "ok" : true,
	

 	

 "type" : "test",
	

 	

 "desc" : "depth",
	

 	

 "text" : "ok 6 - depth"
	

 },
•This is JSON
•Stored in MongoDB
What does that look like?
	

 {
	

 	

 "number" : 6,
	

 	

 "ok" : true,
	

 	

 "type" : "test",
	

 	

 "desc" : "depth",
	

 	

 "text" : "ok 6 - depth"
	

 },
•This is JSON
•Stored in MongoDB
•But it's also TAP!
What does that mean?
Beautiful Tables!
Final
Thoughts
Final
Thoughts
•Play with new toys.
Final
Thoughts
•Play with new toys.
•Think before you code.
Final
Thoughts
•Play with new toys.
•Think before you code.
•Throw stuff away.
Final
Thoughts
•Play with new toys.
•Think before you code.
•Throw stuff away.
•Have bad ideas.
Final
Thoughts
•Play with new toys.
•Think before you code.
•Throw stuff away.
•Have bad ideas.
•Ask stupid questions.
Final
Thoughts
•Play with new toys.
•Think before you code.
•Throw stuff away.
•Have bad ideas.
•Ask stupid questions.
•Have fun.
!
Stupid Questions?
Mike Friedman
(friedo)
friedo@mongodb.com
https://github.com/friedo/cpanci
!

Más contenido relacionado

La actualidad más candente

Packaging is the Worst Way to Distribute Software, Except for Everything Else
Packaging is the Worst Way to Distribute Software, Except for Everything ElsePackaging is the Worst Way to Distribute Software, Except for Everything Else
Packaging is the Worst Way to Distribute Software, Except for Everything Elsemckern
 
Frontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: De débutant à Expert à Fou FurieuxFrontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: De débutant à Expert à Fou FurieuxPhilip Tellis
 
Code reviews vs Pull requests
Code reviews vs Pull requestsCode reviews vs Pull requests
Code reviews vs Pull requestsTim Pettersen
 
Tracking large game assets with Git LFS
Tracking large game assets with Git LFSTracking large game assets with Git LFS
Tracking large game assets with Git LFSTim Pettersen
 
Concurrency in Python
Concurrency in PythonConcurrency in Python
Concurrency in PythonMosky Liu
 
Minimal MVC in JavaScript
Minimal MVC in JavaScriptMinimal MVC in JavaScript
Minimal MVC in JavaScriptMosky Liu
 
Puppet Camp LA 2/19/2015
Puppet Camp LA 2/19/2015Puppet Camp LA 2/19/2015
Puppet Camp LA 2/19/2015ice799
 
Chef Conf 2015: Package Management & Chef
Chef Conf 2015: Package Management & ChefChef Conf 2015: Package Management & Chef
Chef Conf 2015: Package Management & Chefice799
 
Organizing the world of CQ rest infinitive possibilities by Arkadiusz Kita
Organizing the world of CQ rest infinitive possibilities by Arkadiusz KitaOrganizing the world of CQ rest infinitive possibilities by Arkadiusz Kita
Organizing the world of CQ rest infinitive possibilities by Arkadiusz KitaAEM HUB
 
Package manages and Puppet - PuppetConf 2015
Package manages and Puppet - PuppetConf 2015Package manages and Puppet - PuppetConf 2015
Package manages and Puppet - PuppetConf 2015ice799
 
Tracking huge files with Git LFS - LinuxCon 2016
Tracking huge files with Git LFS - LinuxCon 2016Tracking huge files with Git LFS - LinuxCon 2016
Tracking huge files with Git LFS - LinuxCon 2016Tim Pettersen
 
Attacking open source using abandoned resources
Attacking open source using abandoned resourcesAttacking open source using abandoned resources
Attacking open source using abandoned resourcesAdam Baldwin
 
Torquebox @ Charlotte.rb May 2011
Torquebox @ Charlotte.rb May 2011Torquebox @ Charlotte.rb May 2011
Torquebox @ Charlotte.rb May 2011tobiascrawley
 
Torquebox @ Raleigh.rb - April 2011
Torquebox @ Raleigh.rb - April 2011Torquebox @ Raleigh.rb - April 2011
Torquebox @ Raleigh.rb - April 2011tobiascrawley
 
Testing your puppet code
Testing your puppet codeTesting your puppet code
Testing your puppet codeJulien Pivotto
 
Clean Manifests with Puppet::Tidy
Clean Manifests with Puppet::TidyClean Manifests with Puppet::Tidy
Clean Manifests with Puppet::TidyPuppet
 
Using software modules welcome to hell!
Using software modules   welcome to hell!Using software modules   welcome to hell!
Using software modules welcome to hell!Baruch Sadogursky
 
Graph-Tool in Practice
Graph-Tool in PracticeGraph-Tool in Practice
Graph-Tool in PracticeMosky Liu
 
GREAT STEP 1. 테스트 코드를 향한 위대한 발걸음
GREAT STEP 1. 테스트 코드를 향한 위대한 발걸음GREAT STEP 1. 테스트 코드를 향한 위대한 발걸음
GREAT STEP 1. 테스트 코드를 향한 위대한 발걸음Covenant Ko
 

La actualidad más candente (20)

Packaging is the Worst Way to Distribute Software, Except for Everything Else
Packaging is the Worst Way to Distribute Software, Except for Everything ElsePackaging is the Worst Way to Distribute Software, Except for Everything Else
Packaging is the Worst Way to Distribute Software, Except for Everything Else
 
Frontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: De débutant à Expert à Fou FurieuxFrontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: De débutant à Expert à Fou Furieux
 
Code reviews vs Pull requests
Code reviews vs Pull requestsCode reviews vs Pull requests
Code reviews vs Pull requests
 
Tracking large game assets with Git LFS
Tracking large game assets with Git LFSTracking large game assets with Git LFS
Tracking large game assets with Git LFS
 
Concurrency in Python
Concurrency in PythonConcurrency in Python
Concurrency in Python
 
Minimal MVC in JavaScript
Minimal MVC in JavaScriptMinimal MVC in JavaScript
Minimal MVC in JavaScript
 
Puppet Camp LA 2/19/2015
Puppet Camp LA 2/19/2015Puppet Camp LA 2/19/2015
Puppet Camp LA 2/19/2015
 
Chef Conf 2015: Package Management & Chef
Chef Conf 2015: Package Management & ChefChef Conf 2015: Package Management & Chef
Chef Conf 2015: Package Management & Chef
 
Organizing the world of CQ rest infinitive possibilities by Arkadiusz Kita
Organizing the world of CQ rest infinitive possibilities by Arkadiusz KitaOrganizing the world of CQ rest infinitive possibilities by Arkadiusz Kita
Organizing the world of CQ rest infinitive possibilities by Arkadiusz Kita
 
Package manages and Puppet - PuppetConf 2015
Package manages and Puppet - PuppetConf 2015Package manages and Puppet - PuppetConf 2015
Package manages and Puppet - PuppetConf 2015
 
Tracking huge files with Git LFS - LinuxCon 2016
Tracking huge files with Git LFS - LinuxCon 2016Tracking huge files with Git LFS - LinuxCon 2016
Tracking huge files with Git LFS - LinuxCon 2016
 
Attacking open source using abandoned resources
Attacking open source using abandoned resourcesAttacking open source using abandoned resources
Attacking open source using abandoned resources
 
Torquebox @ Charlotte.rb May 2011
Torquebox @ Charlotte.rb May 2011Torquebox @ Charlotte.rb May 2011
Torquebox @ Charlotte.rb May 2011
 
Torquebox @ Raleigh.rb - April 2011
Torquebox @ Raleigh.rb - April 2011Torquebox @ Raleigh.rb - April 2011
Torquebox @ Raleigh.rb - April 2011
 
Testing your puppet code
Testing your puppet codeTesting your puppet code
Testing your puppet code
 
Clean Manifests with Puppet::Tidy
Clean Manifests with Puppet::TidyClean Manifests with Puppet::Tidy
Clean Manifests with Puppet::Tidy
 
Using software modules welcome to hell!
Using software modules   welcome to hell!Using software modules   welcome to hell!
Using software modules welcome to hell!
 
Graph-Tool in Practice
Graph-Tool in PracticeGraph-Tool in Practice
Graph-Tool in Practice
 
GREAT STEP 1. 테스트 코드를 향한 위대한 발걸음
GREAT STEP 1. 테스트 코드를 향한 위대한 발걸음GREAT STEP 1. 테스트 코드를 향한 위대한 발걸음
GREAT STEP 1. 테스트 코드를 향한 위대한 발걸음
 
Logstash and friends
Logstash and friendsLogstash and friends
Logstash and friends
 

Similar a 21st Century CPAN Testing: CPANci

Perl Dist::Surveyor 2011
Perl Dist::Surveyor 2011Perl Dist::Surveyor 2011
Perl Dist::Surveyor 2011Tim Bunce
 
Can you upgrade to Puppet 4.x?
Can you upgrade to Puppet 4.x?Can you upgrade to Puppet 4.x?
Can you upgrade to Puppet 4.x?Martin Alfke
 
perlbrew yapcasia 2010
perlbrew yapcasia 2010perlbrew yapcasia 2010
perlbrew yapcasia 2010Kang-min Liu
 
Pugs: A Perl 6 Implementation
Pugs: A Perl 6 ImplementationPugs: A Perl 6 Implementation
Pugs: A Perl 6 ImplementationAudrey Tang
 
Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?
Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?
Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?NETWAYS
 
Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...
Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...
Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...Puppet
 
Who pulls the strings?
Who pulls the strings?Who pulls the strings?
Who pulls the strings?Ronny
 
Perl Development Environment Tooling
Perl Development Environment ToolingPerl Development Environment Tooling
Perl Development Environment ToolingJason Crome
 
How CPAN Testers helped me improve my module
How CPAN Testers helped me improve my moduleHow CPAN Testers helped me improve my module
How CPAN Testers helped me improve my moduleacme
 
Packaging perl (LPW2010)
Packaging perl (LPW2010)Packaging perl (LPW2010)
Packaging perl (LPW2010)p3castro
 
CPAN 模組二三事
CPAN 模組二三事CPAN 模組二三事
CPAN 模組二三事Lin Yo-An
 
One commit, one release. Continuously delivering a Symfony project.
One commit, one release. Continuously delivering a Symfony project.One commit, one release. Continuously delivering a Symfony project.
One commit, one release. Continuously delivering a Symfony project.Javier López
 
走向开源:提交CPAN模块Step by Step
走向开源:提交CPAN模块Step by Step走向开源:提交CPAN模块Step by Step
走向开源:提交CPAN模块Step by Steppluschen
 
Continuous Integration Testing in Django
Continuous Integration Testing in DjangoContinuous Integration Testing in Django
Continuous Integration Testing in DjangoKevin Harvey
 
CPANTS: Kwalitative website and its tools
CPANTS: Kwalitative website and its toolsCPANTS: Kwalitative website and its tools
CPANTS: Kwalitative website and its toolscharsbar
 
The Popper Experimentation Protocol and CLI tool
The Popper Experimentation Protocol and CLI toolThe Popper Experimentation Protocol and CLI tool
The Popper Experimentation Protocol and CLI toolIvo Jimenez
 

Similar a 21st Century CPAN Testing: CPANci (20)

Nodeconf npm 2011
Nodeconf npm 2011Nodeconf npm 2011
Nodeconf npm 2011
 
Smoking docker
Smoking dockerSmoking docker
Smoking docker
 
Perl Dist::Surveyor 2011
Perl Dist::Surveyor 2011Perl Dist::Surveyor 2011
Perl Dist::Surveyor 2011
 
Unit Testing Lots of Perl
Unit Testing Lots of PerlUnit Testing Lots of Perl
Unit Testing Lots of Perl
 
Can you upgrade to Puppet 4.x?
Can you upgrade to Puppet 4.x?Can you upgrade to Puppet 4.x?
Can you upgrade to Puppet 4.x?
 
perlbrew yapcasia 2010
perlbrew yapcasia 2010perlbrew yapcasia 2010
perlbrew yapcasia 2010
 
Pugs: A Perl 6 Implementation
Pugs: A Perl 6 ImplementationPugs: A Perl 6 Implementation
Pugs: A Perl 6 Implementation
 
Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?
Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?
Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?
 
Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...
Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...
Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...
 
CPAN Training
CPAN TrainingCPAN Training
CPAN Training
 
Who pulls the strings?
Who pulls the strings?Who pulls the strings?
Who pulls the strings?
 
Perl Development Environment Tooling
Perl Development Environment ToolingPerl Development Environment Tooling
Perl Development Environment Tooling
 
How CPAN Testers helped me improve my module
How CPAN Testers helped me improve my moduleHow CPAN Testers helped me improve my module
How CPAN Testers helped me improve my module
 
Packaging perl (LPW2010)
Packaging perl (LPW2010)Packaging perl (LPW2010)
Packaging perl (LPW2010)
 
CPAN 模組二三事
CPAN 模組二三事CPAN 模組二三事
CPAN 模組二三事
 
One commit, one release. Continuously delivering a Symfony project.
One commit, one release. Continuously delivering a Symfony project.One commit, one release. Continuously delivering a Symfony project.
One commit, one release. Continuously delivering a Symfony project.
 
走向开源:提交CPAN模块Step by Step
走向开源:提交CPAN模块Step by Step走向开源:提交CPAN模块Step by Step
走向开源:提交CPAN模块Step by Step
 
Continuous Integration Testing in Django
Continuous Integration Testing in DjangoContinuous Integration Testing in Django
Continuous Integration Testing in Django
 
CPANTS: Kwalitative website and its tools
CPANTS: Kwalitative website and its toolsCPANTS: Kwalitative website and its tools
CPANTS: Kwalitative website and its tools
 
The Popper Experimentation Protocol and CLI tool
The Popper Experimentation Protocol and CLI toolThe Popper Experimentation Protocol and CLI tool
The Popper Experimentation Protocol and CLI tool
 

Más de Mike Friedman

Basic Symbolic Computation in Perl
Basic Symbolic Computation in PerlBasic Symbolic Computation in Perl
Basic Symbolic Computation in PerlMike Friedman
 
Make Your Own Perl with Moops
Make Your Own Perl with MoopsMake Your Own Perl with Moops
Make Your Own Perl with MoopsMike Friedman
 
The Perl API for the Mortally Terrified (beta)
The Perl API for the Mortally Terrified (beta)The Perl API for the Mortally Terrified (beta)
The Perl API for the Mortally Terrified (beta)Mike Friedman
 
Data Modeling for the Real World
Data Modeling for the Real WorldData Modeling for the Real World
Data Modeling for the Real WorldMike Friedman
 
MongoDB Schema Design: Four Real-World Examples
MongoDB Schema Design: Four Real-World ExamplesMongoDB Schema Design: Four Real-World Examples
MongoDB Schema Design: Four Real-World ExamplesMike Friedman
 
Building a MongoDB App with Perl
Building a MongoDB App with PerlBuilding a MongoDB App with Perl
Building a MongoDB App with PerlMike Friedman
 
Building Your First App with MongoDB
Building Your First App with MongoDBBuilding Your First App with MongoDB
Building Your First App with MongoDBMike Friedman
 
Building Scalable, Distributed Job Queues with Redis and Redis::Client
Building Scalable, Distributed Job Queues with Redis and Redis::ClientBuilding Scalable, Distributed Job Queues with Redis and Redis::Client
Building Scalable, Distributed Job Queues with Redis and Redis::ClientMike Friedman
 

Más de Mike Friedman (8)

Basic Symbolic Computation in Perl
Basic Symbolic Computation in PerlBasic Symbolic Computation in Perl
Basic Symbolic Computation in Perl
 
Make Your Own Perl with Moops
Make Your Own Perl with MoopsMake Your Own Perl with Moops
Make Your Own Perl with Moops
 
The Perl API for the Mortally Terrified (beta)
The Perl API for the Mortally Terrified (beta)The Perl API for the Mortally Terrified (beta)
The Perl API for the Mortally Terrified (beta)
 
Data Modeling for the Real World
Data Modeling for the Real WorldData Modeling for the Real World
Data Modeling for the Real World
 
MongoDB Schema Design: Four Real-World Examples
MongoDB Schema Design: Four Real-World ExamplesMongoDB Schema Design: Four Real-World Examples
MongoDB Schema Design: Four Real-World Examples
 
Building a MongoDB App with Perl
Building a MongoDB App with PerlBuilding a MongoDB App with Perl
Building a MongoDB App with Perl
 
Building Your First App with MongoDB
Building Your First App with MongoDBBuilding Your First App with MongoDB
Building Your First App with MongoDB
 
Building Scalable, Distributed Job Queues with Redis and Redis::Client
Building Scalable, Distributed Job Queues with Redis and Redis::ClientBuilding Scalable, Distributed Job Queues with Redis and Redis::Client
Building Scalable, Distributed Job Queues with Redis and Redis::Client
 

Último

Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditSkynet Technologies
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Scott Andery
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 

Último (20)

Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance Audit
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 

21st Century CPAN Testing: CPANci

  • 1. 21st Century CPAN Testing Mike Friedman (friedo) MongoDB, Inc.
  • 2.
  • 3.
  • 5.
  • 6.
  • 11. WAT
  • 13.
  • 17. JSON-like thingy: { "foo": "a string", "bar": 42, "baz": [ 1, 2, "narf", "poit" ], "quux": { "key_1": "w00t.", "key_2": "you get the idea", } }
  • 18. { "foo": "a string", "bar": 42, "baz": [ 1, 2, "narf", "poit" ], "quux": { "key_1": "w00t.", "key_2": "you get the idea", } }
  • 19. { "foo": "a string", "bar": 42, "baz": [ 1, 2, "narf", "poit" ], "quux": { "key_1": "w00t.", "key_2": "you get the idea", } }
  • 20. { "foo": "a string", "bar": 42, "baz": [ 1, 2, "narf", "poit" ], "quux": { "key_1": "w00t.", "key_2": "you get the idea", } } First-Class Objects
  • 27. A lengthy series of bad ideas and stupid questions.
  • 28.
  • 30. Stupid Question No. 1 Who here uses CPAN?
  • 31.
  • 33. Stupid Question No. 2 Who here is a CPAN author?
  • 38. A Brief History •December 18, 1987 •Perl 1.000 released.
  • 39. A Brief History •December 18, 1987 •Perl 1.000 released. •TAP invented.
  • 40. The Test Anything Protocol
  • 41. The Test Anything Protocol 1..42 ok 1 the thing looks good! ok 2 ok 3 $beer isa $drink not ok 4 too much $beer not ok 5 $me->vomit( 'now' ) ...
  • 44. A Brief History •October 17, 1994 •Perl 5.000 released.
  • 45. A Brief History •October 17, 1994 •Perl 5.000 released. •Perl has a module system.
  • 46.
  • 47. # from this require "funcs.pl";
  • 48. # from this require "funcs.pl"; # to this use My::Module;
  • 49.
  • 50. # but under the hood BEGIN { require My::Module; My::Module->import; };
  • 53. A Brief History •October 26, 1995 •CPAN established.
  • 54. A Brief History •October 26, 1995 •CPAN established. •Perl modules are available.
  • 57. A Brief History •May 15, 1997 •Perl 5.004 released.
  • 58. A Brief History •May 15, 1997 •Perl 5.004 released. •CPAN.pm is in the core.
  • 59.
  • 60. # the dark art $ perl -MCPAN -e 'install Foo'
  • 63. A Brief History •May, 1998 •CPAN Testers conceived
  • 64. A Brief History •May, 1998 •CPAN Testers conceived •Automated feedback for authors
  • 65.
  • 66.
  • 67.
  • 68.
  • 71. A Brief History •November 15, 2003 •Perl 5.6.2 released.
  • 72. A Brief History •November 15, 2003 •Perl 5.6.2 released. •Test::More is in the core.
  • 73.
  • 74. use Test::More tests => 3; ok( 42 ); is( $foo, 'my value' ); isnt( 'foo', 'bar' );
  • 77. A Brief History •August 6, 2012 •Mike goes to work for 10gen
  • 78. A Brief History •August 6, 2012 •Mike goes to work for 10gen MongoDB
  • 79.
  • 81. Bad Idea No. 1 Come up with a cool Perl MongoDB project to show off atYAPC!
  • 82. Bad Idea No. 1 Come up with a cool Perl MongoDB project to show off atYAPC! It'll be fun!
  • 83. Bad Idea No. 1 Come up with a cool Perl MongoDB project to show off atYAPC! It'll be fun! promise!
  • 85. CPAN Testers is Wonderful and Amazing
  • 86.
  • 90. Disadvantages: Not real time Not consistent Polluted / Inconsistent environments
  • 91. Disadvantages: Not real time Not consistent Polluted / Inconsistent environments Not all versions on all platforms
  • 92. Perl 5.18 runs on GNU Hurd
  • 93. Perl 5.18 runs on GNU Hurd ?
  • 94. Perl 5.18 runs on GNU Hurd ?
  • 95. Perl 5.18 runs on GNU Hurd ? I ♥ CPAN
  • 101. I want Continuous Integration for the entire CPAN.
  • 102. I want Continuous Integration for the entire CPAN. For platforms I care about.
  • 103.
  • 106.
  • 108. Stupid Question No. 3 How can we test CPAN without the disadvantages of CPAN Testers?
  • 109. Postulate: Every CPAN distribution must be tested in isolation, on a virgin Perl installation untouched by human hands.
  • 110.
  • 111. I release distribution Foo-Awesome-0.0000001
  • 112. I release distribution Foo-Awesome-0.0000001 use Spiffy::Module;
  • 113. I release distribution Foo-Awesome-0.0000001 use Spiffy::Module; Forgotten dependency!
  • 114. I release distribution Foo-Awesome-0.0000001 use Spiffy::Module; Forgotten dependency! What happens?
  • 115. Scenario  I The  tester  hath  not  the  missing   dependency  upon  his  box.
  • 116.
  • 117.
  • 119. Scenario  II The  tester  doth  possess   the  dependency  upon  his  box.
  • 120.
  • 122.
  • 124. Postulate: Every CPAN distribution must be tested in isolation, on a virgin Perl installation untouched by human hands.
  • 125. Postulate: Every CPAN distribution must be tested in isolation, on a virgin Perl installation untouched by human hands. So how do we do that?
  • 129.
  • 131.
  • 133. •Create an EC2 image •Put perlbrew on it
  • 134. •Create an EC2 image •Put perlbrew on it •Install every Perl locally
  • 135. •Create an EC2 image •Put perlbrew on it •Install every Perl locally •Boot an instance for every uploaded distribution
  • 136. •Create an EC2 image •Put perlbrew on it •Install every Perl locally •Boot an instance for every uploaded distribution •Install needed dependencies for the distribution
  • 137. •Create an EC2 image •Put perlbrew on it •Install every Perl locally •Boot an instance for every uploaded distribution •Install needed dependencies for the distribution •Run the tests and report the results
  • 138. •Create an EC2 image •Put perlbrew on it •Install every Perl locally •Boot an instance for every uploaded distribution •Install needed dependencies for the distribution •Run the tests and report the results •Shut down the instance
  • 139.
  • 140. Uh-oh.
  • 141.
  • 143. Stupid Question No. 4 How can we do this on one instance?
  • 147. App::cpanminus •Self-contained •That is, the cpanm script is self-contained
  • 148. App::cpanminus •Self-contained •That is, the cpanm script is self-contained •via App::FatPacker
  • 150. App::cpanminus That means the same cpanm can be run by any perl
  • 151. App::cpanminus That means the same cpanm can be run by any perl perlbrew switch master curl -L http://cpanmin.us/ | perl - App::cpanminus ln -s ~/perl5/perlbrew/perls/master/bin/cpanm ./cpanm ~/perl5/perlbrew/perls/perl-5.8.9/bin/perl cpanm ~/perl5/perlbrew/perls/perl-5.10.1/bin/perl cpanm ~/perl5/perlbrew/perls/perl-5.12.5/bin/perl cpanm ~/perl5/perlbrew/perls/perl-5.14.4/bin/perl cpanm ~/perl5/perlbrew/perls/perl-5.16.3/bin/perl cpanm ~/perl5/perlbrew/perls/perl-5.18.0/bin/perl cpanm ~/perl5/perlbrew/perls/perl-5.19.0/bin/perl cpanm
  • 152.
  • 153. •Use perlbrew to install a "master" perl
  • 154. •Use perlbrew to install a "master" perl •Use it again to install "virgin" perls of every major version
  • 155. •Use perlbrew to install a "master" perl •Use it again to install "virgin" perls of every major version •Use the master perl to install everything from CPAN that makes CPANci work
  • 156. •Use perlbrew to install a "master" perl •Use it again to install "virgin" perls of every major version •Use the master perl to install everything from CPAN that makes CPANci work •For each distribution, create a temp directory
  • 157. •Use perlbrew to install a "master" perl •Use it again to install "virgin" perls of every major version •Use the master perl to install everything from CPAN that makes CPANci work •For each distribution, create a temp directory •Tell cpanminus to install dependencies there, as if for local::lib
  • 158. •Use perlbrew to install a "master" perl •Use it again to install "virgin" perls of every major version •Use the master perl to install everything from CPAN that makes CPANci work •For each distribution, create a temp directory •Tell cpanminus to install dependencies there, as if for local::lib •Run tests and report results
  • 159. •Use perlbrew to install a "master" perl •Use it again to install "virgin" perls of every major version •Use the master perl to install everything from CPAN that makes CPANci work •For each distribution, create a temp directory •Tell cpanminus to install dependencies there, as if for local::lib •Run tests and report results •Delete temp directory, leaving each perl untouched!
  • 160. What does that look like? The "fetcher" grabs the latest distribution URLs from MetaCPAN's RSS feed. my $xml = XML::LibXML->load_xml( string => $self->ua->get( $self->rss_base )->decoded_content ); my @dists = map { my $u = URI->new( $_->getAttribute( 'rdf:resource' ) ); $u->host( 'api.metacpan.org' ); $u->path( 'v0' . $u->path ); $u; } $xml->findnodes( '//rdf:li' );
  • 161. What does that look like? The "fetcher" grabs the latest distribution URLs from MetaCPAN's RSS feed. my $xml = XML::LibXML->load_xml( string => $self->ua->get( $self->rss_base )->decoded_content ); my @dists = map { my $u = URI->new( $_->getAttribute( 'rdf:resource' ) ); $u->host( 'api.metacpan.org' ); $u->path( 'v0' . $u->path ); $u; } $xml->findnodes( '//rdf:li' );
  • 162. What does that look like? The "fetcher" grabs the latest distribution URLs from MetaCPAN's RSS feed. my $xml = XML::LibXML->load_xml( string => $self->ua->get( $self->rss_base )->decoded_content ); my @dists = map { my $u = URI->new( $_->getAttribute( 'rdf:resource' ) ); $u->host( 'api.metacpan.org' ); $u->path( 'v0' . $u->path ); $u; } $xml->findnodes( '//rdf:li' );
  • 163. What does that look like? The "fetcher" grabs the latest distribution URLs from MetaCPAN's RSS feed. my $xml = XML::LibXML->load_xml( string => $self->ua->get( $self->rss_base )->decoded_content ); my @dists = map { my $u = URI->new( $_->getAttribute( 'rdf:resource' ) ); $u->host( 'api.metacpan.org' ); $u->path( 'v0' . $u->path ); $u; } $xml->findnodes( '//rdf:li' );
  • 164. What does that look like? We retrieve the distribution metadata from the MetaCPAN JSON API and save it to MongoDB. foreach my $dist( @dists ) { my $fetched_data = decode_json $self->ua->get( $dist )->decoded_content; my %ins = ( _id => 'cpan/' . $name, fetched => DateTime->now, meta => $fetched_data ); $coll->insert( %ins ); }
  • 165. What does that look like? We retrieve the distribution metadata from the MetaCPAN JSON API and save it to MongoDB. foreach my $dist( @dists ) { my $fetched_data = decode_json $self->ua->get( $dist )->decoded_content; my %ins = ( _id => 'cpan/' . $name, fetched => DateTime->now, meta => $fetched_data ); $coll->insert( %ins ); }
  • 166. What does that look like? We retrieve the distribution metadata from the MetaCPAN JSON API and save it to MongoDB. foreach my $dist( @dists ) { my $fetched_data = decode_json $self->ua->get( $dist )->decoded_content; my %ins = ( _id => 'cpan/' . $name, fetched => DateTime->now, meta => $fetched_data ); $coll->insert( %ins ); }
  • 167. What does that look like? We retrieve the distribution metadata from the MetaCPAN JSON API and save it to MongoDB. foreach my $dist( @dists ) { my $fetched_data = decode_json $self->ua->get( $dist )->decoded_content; my %ins = ( _id => 'cpan/' . $name, fetched => DateTime->now, meta => $fetched_data ); $coll->insert( %ins ); }
  • 168. What does that look like? We retrieve the distribution metadata from the MetaCPAN JSON API and save it to MongoDB. foreach my $dist( @dists ) { my $fetched_data = decode_json $self->ua->get( $dist )->decoded_content; my %ins = ( _id => 'cpan/' . $name, fetched => DateTime->now, meta => $fetched_data ); $coll->insert( %ins ); }
  • 169. What does that look like? We extract the archive in a specific "work" directory for each perl. Then use a temp directory for building and installing dependencies. foreach my $perl ( @{ $self->perls } ) { my $workdir = catdir $self->home, 'work', $perl, $dist; chdir $workdir; }
  • 170. What does that look like? We extract the archive in a specific "work" directory for each perl. Then use a temp directory for building and installing dependencies. foreach my $perl ( @{ $self->perls } ) { my $workdir = catdir $self->home, 'work', $perl, $dist; chdir $workdir; }
  • 171. What does that look like? We extract the archive in a specific "work" directory for each perl. Then use a temp directory for building and installing dependencies. foreach my $perl ( @{ $self->perls } ) { my $workdir = catdir $self->home, 'work', $perl, $dist; chdir $workdir; }
  • 172. What does that look like? We extract the archive in a specific "work" directory for each perl. Then use a temp directory for building and installing dependencies. foreach my $perl ( @{ $self->perls } ) { my $workdir = catdir $self->home, 'work', $perl, $dist; chdir $workdir; }
  • 173. What does that look like? Use a specific perl binary to run cpanm and install dependencies, with no tests, to the temp directory. Then we parse the cpanm log on stderr my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $pid = open3 $wtr, $rdr, $err, $plbin, $self->cpanm, '--installdeps', '--notest', '-L', $dist_tmp, '.'; my $results = $self->_read_cpanm_deps_log( $err );
  • 174. What does that look like? Use a specific perl binary to run cpanm and install dependencies, with no tests, to the temp directory. Then we parse the cpanm log on stderr my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $pid = open3 $wtr, $rdr, $err, $plbin, $self->cpanm, '--installdeps', '--notest', '-L', $dist_tmp, '.'; my $results = $self->_read_cpanm_deps_log( $err );
  • 175. What does that look like? Use a specific perl binary to run cpanm and install dependencies, with no tests, to the temp directory. Then we parse the cpanm log on stderr my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $pid = open3 $wtr, $rdr, $err, $plbin, $self->cpanm, '--installdeps', '--notest', '-L', $dist_tmp, '.'; my $results = $self->_read_cpanm_deps_log( $err );
  • 176. What does that look like? Use a specific perl binary to run cpanm and install dependencies, with no tests, to the temp directory. Then we parse the cpanm log on stderr my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $pid = open3 $wtr, $rdr, $err, $plbin, $self->cpanm, '--installdeps', '--notest', '-L', $dist_tmp, '.'; my $results = $self->_read_cpanm_deps_log( $err );
  • 177. What does that look like? Use a specific perl binary to run cpanm and install dependencies, with no tests, to the temp directory. Then we parse the cpanm log on stderr my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $pid = open3 $wtr, $rdr, $err, $plbin, $self->cpanm, '--installdeps', '--notest', '-L', $dist_tmp, '.'; my $results = $self->_read_cpanm_deps_log( $err );
  • 178. What does that look like? Use a specific perl binary to run cpanm and install dependencies, with no tests, to the temp directory. Then we parse the cpanm log on stderr my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $pid = open3 $wtr, $rdr, $err, $plbin, $self->cpanm, '--installdeps', '--notest', '-L', $dist_tmp, '.'; my $results = $self->_read_cpanm_deps_log( $err );
  • 179. "deps" : { "log" : [ { "indent" : 0, "type" : "working-on", "line" : "--> Working on .n" }, { "line" : "Configuring Lingua-EN-NamedEntity-1.92 ... OKn", "type" : "config", "indent" : 1 }, { "type" : "found-deps", "indent" : 1, "line" : "==> Found dependencies: Lingua::Stem::En, DB_File, LWP::Simplen" }, { "indent" : 1, "type" : "working-on", "line" : "--> Working on Lingua::Stem::Enn" }, { "indent" : 2, "type" : "fetch", "line" : "Fetching http://www.cpan.org/authors/id/S/SN/SNOWHARE/Lingua- Stem-0.84.tar.gz ... OKn" }, What does that look like?
  • 180. What does that look like? Use a specific perl to run each test file, save the TAP output and any errors, and use the exit status to determine if it passed. foreach my $test( @tests ) { my @test_results; my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $idir = catdir $dist_tmp, 'lib', 'perl5'; my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test; my ( $tap_out, $errors ); { local $/; $tap_out = readline $rdr; $errors = readline $err; } waitpid $pid, 0; my $passed = ( ( $? >> 8 ) == 0 ) true : false ); }
  • 181. What does that look like? Use a specific perl to run each test file, save the TAP output and any errors, and use the exit status to determine if it passed. foreach my $test( @tests ) { my @test_results; my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $idir = catdir $dist_tmp, 'lib', 'perl5'; my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test; my ( $tap_out, $errors ); { local $/; $tap_out = readline $rdr; $errors = readline $err; } waitpid $pid, 0; my $passed = ( ( $? >> 8 ) == 0 ) true : false ); }
  • 182. What does that look like? Use a specific perl to run each test file, save the TAP output and any errors, and use the exit status to determine if it passed. foreach my $test( @tests ) { my @test_results; my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $idir = catdir $dist_tmp, 'lib', 'perl5'; my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test; my ( $tap_out, $errors ); { local $/; $tap_out = readline $rdr; $errors = readline $err; } waitpid $pid, 0; my $passed = ( ( $? >> 8 ) == 0 ) true : false ); }
  • 183. What does that look like? Use a specific perl to run each test file, save the TAP output and any errors, and use the exit status to determine if it passed. foreach my $test( @tests ) { my @test_results; my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $idir = catdir $dist_tmp, 'lib', 'perl5'; my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test; my ( $tap_out, $errors ); { local $/; $tap_out = readline $rdr; $errors = readline $err; } waitpid $pid, 0; my $passed = ( ( $? >> 8 ) == 0 ) true : false ); }
  • 184. What does that look like? Use a specific perl to run each test file, save the TAP output and any errors, and use the exit status to determine if it passed. foreach my $test( @tests ) { my @test_results; my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $idir = catdir $dist_tmp, 'lib', 'perl5'; my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test; my ( $tap_out, $errors ); { local $/; $tap_out = readline $rdr; $errors = readline $err; } waitpid $pid, 0; my $passed = ( ( $? >> 8 ) == 0 ) true : false ); }
  • 185. What does that look like? Use a specific perl to run each test file, save the TAP output and any errors, and use the exit status to determine if it passed. foreach my $test( @tests ) { my @test_results; my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $idir = catdir $dist_tmp, 'lib', 'perl5'; my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test; my ( $tap_out, $errors ); { local $/; $tap_out = readline $rdr; $errors = readline $err; } waitpid $pid, 0; my $passed = ( ( $? >> 8 ) == 0 ) true : false ); }
  • 186. What does that look like? Use a specific perl to run each test file, save the TAP output and any errors, and use the exit status to determine if it passed. foreach my $test( @tests ) { my @test_results; my $plbin = catfile $self->pldir, $perl, 'bin', 'perl'; my $idir = catdir $dist_tmp, 'lib', 'perl5'; my $pid = open3 $wtr, $rdr, $plbin, '-I', $idir, $test; my ( $tap_out, $errors ); { local $/; $tap_out = readline $rdr; $errors = readline $err; } waitpid $pid, 0; my $passed = ( ( $? >> 8 ) == 0 ) true : false ); }
  • 187. What does that look like? Parse the TAP output of each test into a structure which can be saved in MongoDB eval { my $parser = TAP::Parser->new( { source => $tap_out } ); while( my $result = $parser->next ) { push @test_results, { text => $result->as_string, ok => ( $result_is_ok ? true : false ), type => $result->type, $result->type eq 'test' ? ( number => $result->number, desc => ( $result->description =~ s/^- //r ) ) : ( ), }; } };
  • 188. What does that look like? Parse the TAP output of each test into a structure which can be saved in MongoDB eval { my $parser = TAP::Parser->new( { source => $tap_out } ); while( my $result = $parser->next ) { push @test_results, { text => $result->as_string, ok => ( $result_is_ok ? true : false ), type => $result->type, $result->type eq 'test' ? ( number => $result->number, desc => ( $result->description =~ s/^- //r ) ) : ( ), }; } };
  • 189. What does that look like? Parse the TAP output of each test into a structure which can be saved in MongoDB eval { my $parser = TAP::Parser->new( { source => $tap_out } ); while( my $result = $parser->next ) { push @test_results, { text => $result->as_string, ok => ( $result_is_ok ? true : false ), type => $result->type, $result->type eq 'test' ? ( number => $result->number, desc => ( $result->description =~ s/^- //r ) ) : ( ), }; } };
  • 190. What does that look like? Parse the TAP output of each test into a structure which can be saved in MongoDB eval { my $parser = TAP::Parser->new( { source => $tap_out } ); while( my $result = $parser->next ) { push @test_results, { text => $result->as_string, ok => ( $result_is_ok ? true : false ), type => $result->type, $result->type eq 'test' ? ( number => $result->number, desc => ( $result->description =~ s/^- //r ) ) : ( ), }; } };
  • 191. What does that look like? Parse the TAP output of each test into a structure which can be saved in MongoDB eval { my $parser = TAP::Parser->new( { source => $tap_out } ); while( my $result = $parser->next ) { push @test_results, { text => $result->as_string, ok => ( $result_is_ok ? true : false ), type => $result->type, $result->type eq 'test' ? ( number => $result->number, desc => ( $result->description =~ s/^- //r ) ) : ( ), }; } };
  • 192. What does that look like? Parse the TAP output of each test into a structure which can be saved in MongoDB eval { my $parser = TAP::Parser->new( { source => $tap_out } ); while( my $result = $parser->next ) { push @test_results, { text => $result->as_string, ok => ( $result_is_ok ? true : false ), type => $result->type, $result->type eq 'test' ? ( number => $result->number, desc => ( $result->description =~ s/^- //r ) ) : ( ), }; } };
  • 193. What does that look like? Parse the TAP output of each test into a structure which can be saved in MongoDB eval { my $parser = TAP::Parser->new( { source => $tap_out } ); while( my $result = $parser->next ) { push @test_results, { text => $result->as_string, ok => ( $result_is_ok ? true : false ), type => $result->type, $result->type eq 'test' ? ( number => $result->number, desc => ( $result->description =~ s/^- //r ) ) : ( ), }; } };
  • 194. What does that look like? Parse the TAP output of each test into a structure which can be saved in MongoDB eval { my $parser = TAP::Parser->new( { source => $tap_out } ); while( my $result = $parser->next ) { push @test_results, { text => $result->as_string, ok => ( $result_is_ok ? true : false ), type => $result->type, $result->type eq 'test' ? ( number => $result->number, desc => ( $result->description =~ s/^- //r ) ) : ( ), }; } };
  • 195. What does that look like? Parse the TAP output of each test into a structure which can be saved in MongoDB eval { my $parser = TAP::Parser->new( { source => $tap_out } ); while( my $result = $parser->next ) { push @test_results, { text => $result->as_string, ok => ( $result_is_ok ? true : false ), type => $result->type, $result->type eq 'test' ? ( number => $result->number, desc => ( $result->description =~ s/^- //r ) ) : ( ), }; } };
  • 196. What does that look like? Parse the TAP output of each test into a structure which can be saved in MongoDB eval { my $parser = TAP::Parser->new( { source => $tap_out } ); while( my $result = $parser->next ) { push @test_results, { text => $result->as_string, ok => ( $result_is_ok ? true : false ), type => $result->type, $result->type eq 'test' ? ( number => $result->number, desc => ( $result->description =~ s/^- //r ) ) : ( ), }; } };
  • 197. What does that look like? Parse the TAP output of each test into a structure which can be saved in MongoDB eval { my $parser = TAP::Parser->new( { source => $tap_out } ); while( my $result = $parser->next ) { push @test_results, { text => $result->as_string, ok => ( $result_is_ok ? true : false ), type => $result->type, $result->type eq 'test' ? ( number => $result->number, desc => ( $result->description =~ s/^- //r ) ) : ( ), }; } };
  • 198. What does that look like?
  • 199. What does that look like? { "number" : 6, "ok" : true, "type" : "test", "desc" : "depth", "text" : "ok 6 - depth" },
  • 200. What does that look like? { "number" : 6, "ok" : true, "type" : "test", "desc" : "depth", "text" : "ok 6 - depth" }, •This is JSON
  • 201. What does that look like? { "number" : 6, "ok" : true, "type" : "test", "desc" : "depth", "text" : "ok 6 - depth" }, •This is JSON •Stored in MongoDB
  • 202. What does that look like? { "number" : 6, "ok" : true, "type" : "test", "desc" : "depth", "text" : "ok 6 - depth" }, •This is JSON •Stored in MongoDB •But it's also TAP!
  • 203. What does that mean?
  • 207. Final Thoughts •Play with new toys. •Think before you code.
  • 208. Final Thoughts •Play with new toys. •Think before you code. •Throw stuff away.
  • 209. Final Thoughts •Play with new toys. •Think before you code. •Throw stuff away. •Have bad ideas.
  • 210. Final Thoughts •Play with new toys. •Think before you code. •Throw stuff away. •Have bad ideas. •Ask stupid questions.
  • 211. Final Thoughts •Play with new toys. •Think before you code. •Throw stuff away. •Have bad ideas. •Ask stupid questions. •Have fun.
  • 212. !