21st century cpan testing: cpanci

213
21st Century CPAN Testing Mike Friedman (friedo) MongoDB, Inc.

Upload: mike-friedman

Post on 17-May-2015

483 views

Category:

Technology


2 download

DESCRIPTION

Presented at the 2013 Pittsburgh Perl Workshop, this talk discusses the history and technology behind Mike Friedman's CPANci project.

TRANSCRIPT

Page 1: 21st Century CPAN Testing: CPANci

21st CenturyCPAN Testing

Mike Friedman(friedo)MongoDB, Inc.

Page 2: 21st Century CPAN Testing: CPANci
Page 3: 21st Century CPAN Testing: CPANci
Page 4: 21st Century CPAN Testing: CPANci

Aug. 27, 2013:

Page 5: 21st Century CPAN Testing: CPANci
Page 6: 21st Century CPAN Testing: CPANci
Page 7: 21st Century CPAN Testing: CPANci

, Inc.

Page 8: 21st Century CPAN Testing: CPANci

, Inc.

makes

(the database)

Page 9: 21st Century CPAN Testing: CPANci

, Inc.

makes

(the database)

employs

Mike Friedman(friedo)

Page 10: 21st Century CPAN Testing: CPANci

, Inc.

makes

(the database)

employs

Mike Friedman(friedo)

Page 11: 21st Century CPAN Testing: CPANci

WAT

Page 12: 21st Century CPAN Testing: CPANci

What is MongoDB?

Page 13: 21st Century CPAN Testing: CPANci
Page 14: 21st Century CPAN Testing: CPANci

Open Source Non-relational Horizontally

Scalable

Document-oriented Fast Database

Fault-tolerant CoolSchemaless

Page 15: 21st Century CPAN Testing: CPANci

Document-oriented

Page 16: 21st Century CPAN Testing: CPANci

Document-oriented

Page 17: 21st Century CPAN Testing: CPANci

JSON-like thingy:

{ "foo": "a string", "bar": 42, "baz": [ 1, 2, "narf", "poit" ], "quux": { "key_1": "w00t.", "key_2": "you get the idea", }}

Page 18: 21st Century CPAN Testing: CPANci

{ "foo": "a string", "bar": 42, "baz": [ 1, 2, "narf", "poit" ], "quux": { "key_1": "w00t.", "key_2": "you get the idea", }}

Page 19: 21st Century CPAN Testing: CPANci

{ "foo": "a string", "bar": 42, "baz": [ 1, 2, "narf", "poit" ], "quux": { "key_1": "w00t.", "key_2": "you get the idea", }}

Page 20: 21st Century CPAN Testing: CPANci

{ "foo": "a string", "bar": 42, "baz": [ 1, 2, "narf", "poit" ], "quux": { "key_1": "w00t.", "key_2": "you get the idea", }}

First-Class Objects

Page 21: 21st Century CPAN Testing: CPANci

First-Class Objects

Page 22: 21st Century CPAN Testing: CPANci

First-Class Objects

Page 23: 21st Century CPAN Testing: CPANci

First-Class Objects

Queryable

Page 24: 21st Century CPAN Testing: CPANci

First-Class Objects

Queryable Indexable

Page 25: 21st Century CPAN Testing: CPANci

First-Class Objects

Queryable Indexable Updateable

Page 26: 21st Century CPAN Testing: CPANci

Testing CPANin the

21st Century

Page 27: 21st Century CPAN Testing: CPANci

A lengthy series of bad ideas and stupid

questions.

Page 28: 21st Century CPAN Testing: CPANci
Page 29: 21st Century CPAN Testing: CPANci

Stupid Question No. 1

Page 30: 21st Century CPAN Testing: CPANci

Stupid Question No. 1Who here uses CPAN?

Page 31: 21st Century CPAN Testing: CPANci
Page 32: 21st Century CPAN Testing: CPANci

Stupid Question No. 2

Page 33: 21st Century CPAN Testing: CPANci

Stupid Question No. 2Who here is a CPAN author?

Page 34: 21st Century CPAN Testing: CPANci

What’s this about, anyway?

Page 35: 21st Century CPAN Testing: CPANci

What’s this about, anyway?

CPANci

Page 36: 21st Century CPAN Testing: CPANci

A Brief History

Page 37: 21st Century CPAN Testing: CPANci

A Brief History

•December 18, 1987

Page 38: 21st Century CPAN Testing: CPANci

A Brief History

•December 18, 1987•Perl 1.000 released.

Page 39: 21st Century CPAN Testing: CPANci

A Brief History

•December 18, 1987•Perl 1.000 released.•TAP invented.

Page 40: 21st Century CPAN Testing: CPANci

The Test Anything Protocol

Page 41: 21st Century CPAN Testing: CPANci

The Test Anything Protocol

1..42ok 1 the thing looks good!ok 2ok 3 $beer isa $drinknot ok 4 too much $beernot ok 5 $me->vomit( 'now' )...

Page 42: 21st Century CPAN Testing: CPANci

A Brief History

Page 43: 21st Century CPAN Testing: CPANci

A Brief History

•October 17, 1994

Page 44: 21st Century CPAN Testing: CPANci

A Brief History

•October 17, 1994•Perl 5.000 released.

Page 45: 21st Century CPAN Testing: CPANci

A Brief History

•October 17, 1994•Perl 5.000 released.•Perl has a module system.

Page 46: 21st Century CPAN Testing: CPANci
Page 47: 21st Century CPAN Testing: CPANci

# from thisrequire "funcs.pl";

Page 48: 21st Century CPAN Testing: CPANci

# from thisrequire "funcs.pl";

# to thisuse My::Module;

Page 49: 21st Century CPAN Testing: CPANci
Page 50: 21st Century CPAN Testing: CPANci

# but under the hoodBEGIN { require My::Module; My::Module->import;};

Page 51: 21st Century CPAN Testing: CPANci

A Brief History

Page 52: 21st Century CPAN Testing: CPANci

A Brief History

•October 26, 1995

Page 53: 21st Century CPAN Testing: CPANci

A Brief History

•October 26, 1995•CPAN established.

Page 54: 21st Century CPAN Testing: CPANci

A Brief History

•October 26, 1995•CPAN established.•Perl modules are available.

Page 55: 21st Century CPAN Testing: CPANci

A Brief History

Page 56: 21st Century CPAN Testing: CPANci

A Brief History

•May 15, 1997

Page 57: 21st Century CPAN Testing: CPANci

A Brief History

•May 15, 1997•Perl 5.004 released.

Page 58: 21st Century CPAN Testing: CPANci

A Brief History

•May 15, 1997•Perl 5.004 released.•CPAN.pm is in the core.

Page 59: 21st Century CPAN Testing: CPANci
Page 60: 21st Century CPAN Testing: CPANci

# the dark art$ perl -MCPAN -e 'install Foo'

Page 61: 21st Century CPAN Testing: CPANci

A Brief History

Page 62: 21st Century CPAN Testing: CPANci

A Brief History

•May, 1998

Page 63: 21st Century CPAN Testing: CPANci

A Brief History

•May, 1998•CPAN Testers conceived

Page 64: 21st Century CPAN Testing: CPANci

A Brief History

•May, 1998•CPAN Testers conceived•Automated feedback for authors

Page 65: 21st Century CPAN Testing: CPANci
Page 66: 21st Century CPAN Testing: CPANci
Page 67: 21st Century CPAN Testing: CPANci
Page 68: 21st Century CPAN Testing: CPANci
Page 69: 21st Century CPAN Testing: CPANci

A Brief History

Page 70: 21st Century CPAN Testing: CPANci

A Brief History

•November 15, 2003

Page 71: 21st Century CPAN Testing: CPANci

A Brief History

•November 15, 2003•Perl 5.6.2 released.

Page 72: 21st Century CPAN Testing: CPANci

A Brief History

•November 15, 2003•Perl 5.6.2 released.•Test::More is in the core.

Page 73: 21st Century CPAN Testing: CPANci
Page 74: 21st Century CPAN Testing: CPANci

use Test::More tests => 3;

ok( 42 );is( $foo, 'my value' );isnt( 'foo', 'bar' );

Page 75: 21st Century CPAN Testing: CPANci

A Brief History

Page 76: 21st Century CPAN Testing: CPANci

A Brief History

•August 6, 2012

Page 77: 21st Century CPAN Testing: CPANci

A Brief History

•August 6, 2012•Mike goes to work for 10gen

Page 78: 21st Century CPAN Testing: CPANci

A Brief History

•August 6, 2012•Mike goes to work for 10gen MongoDB

Page 79: 21st Century CPAN Testing: CPANci
Page 80: 21st Century CPAN Testing: CPANci

Bad Idea No. 1

Page 81: 21st Century CPAN Testing: CPANci

Bad Idea No. 1Come up with a cool Perl MongoDB project

to show off at YAPC!

Page 82: 21st Century CPAN Testing: CPANci

Bad Idea No. 1Come up with a cool Perl MongoDB project

to show off at YAPC!

It'll be fun!

Page 83: 21st Century CPAN Testing: CPANci

Bad Idea No. 1Come up with a cool Perl MongoDB project

to show off at YAPC!

It'll be fun!promise!

Page 84: 21st Century CPAN Testing: CPANci

CPAN Testers

Page 85: 21st Century CPAN Testing: CPANci

CPAN Testers is Wonderful and Amazing

Page 86: 21st Century CPAN Testing: CPANci
Page 87: 21st Century CPAN Testing: CPANci

Disadvantages:

Page 88: 21st Century CPAN Testing: CPANci

Disadvantages:Not real time

Page 89: 21st Century CPAN Testing: CPANci

Disadvantages:Not real timeNot consistent

Page 90: 21st Century CPAN Testing: CPANci

Disadvantages:Not real timeNot consistentPolluted / Inconsistent

environments

Page 91: 21st Century CPAN Testing: CPANci

Disadvantages:Not real timeNot consistentPolluted / Inconsistent

environmentsNot all versions on all platforms

Page 92: 21st Century CPAN Testing: CPANci

Perl 5.18 runs on

GNU Hurd

Page 93: 21st Century CPAN Testing: CPANci

Perl 5.18 runs on

GNU Hurd?

Page 94: 21st Century CPAN Testing: CPANci

Perl 5.18 runs on

GNU Hurd?

Page 95: 21st Century CPAN Testing: CPANci

Perl 5.18 runs on

GNU Hurd?I ♥

CPAN

Page 96: 21st Century CPAN Testing: CPANci

I don't care.

Page 97: 21st Century CPAN Testing: CPANci

I care about:

Page 98: 21st Century CPAN Testing: CPANci

I care about:

Page 99: 21st Century CPAN Testing: CPANci

I care about:

Page 100: 21st Century CPAN Testing: CPANci

I care about:

Page 101: 21st Century CPAN Testing: CPANci

I want Continuous Integrationfor the entire CPAN.

Page 102: 21st Century CPAN Testing: CPANci

I want Continuous Integrationfor the entire CPAN.

For platforms I care about.

Page 103: 21st Century CPAN Testing: CPANci
Page 104: 21st Century CPAN Testing: CPANci

Bad Idea No. 2

Page 105: 21st Century CPAN Testing: CPANci

CPANci.org

Bad Idea No. 2

Page 106: 21st Century CPAN Testing: CPANci
Page 107: 21st Century CPAN Testing: CPANci

Stupid Question No. 3

Page 108: 21st Century CPAN Testing: CPANci

Stupid Question No. 3How can we test CPAN without the

disadvantages of CPAN Testers?

Page 109: 21st Century CPAN Testing: CPANci

Postulate:

Every CPAN distribution must be tested in isolation, on a virgin Perl installation untouched by human hands.

Page 110: 21st Century CPAN Testing: CPANci
Page 111: 21st Century CPAN Testing: CPANci

I release distribution Foo-Awesome-0.0000001

Page 112: 21st Century CPAN Testing: CPANci

I release distribution Foo-Awesome-0.0000001

use Spiffy::Module;

Page 113: 21st Century CPAN Testing: CPANci

I release distribution Foo-Awesome-0.0000001

use Spiffy::Module;

Forgotten dependency!

Page 114: 21st Century CPAN Testing: CPANci

I release distribution Foo-Awesome-0.0000001

use Spiffy::Module;

Forgotten dependency!

What happens?

Page 115: 21st Century CPAN Testing: CPANci

Scenario  IThe  tester  hath  not  the  missing  

dependency  upon  his  box.

Page 116: 21st Century CPAN Testing: CPANci
Page 117: 21st Century CPAN Testing: CPANci
Page 118: 21st Century CPAN Testing: CPANci

FAIL- mail

Page 119: 21st Century CPAN Testing: CPANci

Scenario  IIThe  tester  doth  possess  

the  dependency  upon  his  box.

Page 120: 21st Century CPAN Testing: CPANci
Page 121: 21st Century CPAN Testing: CPANci

EVERYTHING IS FINE.

Page 122: 21st Century CPAN Testing: CPANci
Page 123: 21st Century CPAN Testing: CPANci

NOT FINE.

Page 124: 21st Century CPAN Testing: CPANci

Postulate:

Every CPAN distribution must be tested in isolation, on a virgin Perl installation untouched by human hands.

Page 125: 21st Century CPAN Testing: CPANci

Postulate:

Every CPAN distribution must be tested in isolation, on a virgin Perl installation untouched by human hands.

So how do we do that?

Page 126: 21st Century CPAN Testing: CPANci

perlbrew

Page 127: 21st Century CPAN Testing: CPANci

Virtualization

Page 128: 21st Century CPAN Testing: CPANci

Virtualization

Whoa!

Page 129: 21st Century CPAN Testing: CPANci
Page 130: 21st Century CPAN Testing: CPANci

Bad Idea No. 3

Page 131: 21st Century CPAN Testing: CPANci
Page 132: 21st Century CPAN Testing: CPANci

•Create an EC2 image

Page 133: 21st Century CPAN Testing: CPANci

•Create an EC2 image•Put perlbrew on it

Page 134: 21st Century CPAN Testing: CPANci

•Create an EC2 image•Put perlbrew on it•Install every Perl locally

Page 135: 21st Century CPAN Testing: CPANci

•Create an EC2 image•Put perlbrew on it•Install every Perl locally•Boot an instance for every uploaded distribution

Page 136: 21st Century CPAN Testing: CPANci

•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

Page 137: 21st Century CPAN Testing: CPANci

•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

Page 138: 21st Century CPAN Testing: CPANci

•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

Page 139: 21st Century CPAN Testing: CPANci
Page 140: 21st Century CPAN Testing: CPANci

Uh-oh.

Page 141: 21st Century CPAN Testing: CPANci
Page 142: 21st Century CPAN Testing: CPANci

Stupid Question No. 4

Page 143: 21st Century CPAN Testing: CPANci

Stupid Question No. 4How can we do this on one instance?

Page 144: 21st Century CPAN Testing: CPANci

local::lib

cpanminus

Page 145: 21st Century CPAN Testing: CPANci

App::cpanminus

Page 146: 21st Century CPAN Testing: CPANci

App::cpanminus

•Self-contained

Page 147: 21st Century CPAN Testing: CPANci

App::cpanminus

•Self-contained•That is, the cpanm script is self-contained

Page 148: 21st Century CPAN Testing: CPANci

App::cpanminus

•Self-contained•That is, the cpanm script is self-contained•via App::FatPacker

Page 149: 21st Century CPAN Testing: CPANci

App::cpanminus

Page 150: 21st Century CPAN Testing: CPANci

App::cpanminusThat means the same cpanm can be run by any perl

Page 151: 21st Century CPAN Testing: CPANci

App::cpanminusThat means the same cpanm can be run by any perl

perlbrew switch mastercurl -L http://cpanmin.us/ | perl - App::cpanminusln -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

Page 152: 21st Century CPAN Testing: CPANci
Page 153: 21st Century CPAN Testing: CPANci

•Use perlbrew to install a "master" perl

Page 154: 21st Century CPAN Testing: CPANci

•Use perlbrew to install a "master" perl•Use it again to install "virgin" perls of every major version

Page 155: 21st Century CPAN Testing: CPANci

•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

Page 156: 21st Century CPAN Testing: CPANci

•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

Page 157: 21st Century CPAN Testing: CPANci

•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

Page 158: 21st Century CPAN Testing: CPANci

•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

Page 159: 21st Century CPAN Testing: CPANci

•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!

Page 160: 21st Century CPAN Testing: CPANci

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' );

Page 161: 21st Century CPAN Testing: CPANci

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' );

Page 162: 21st Century CPAN Testing: CPANci

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' );

Page 163: 21st Century CPAN Testing: CPANci

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' );

Page 164: 21st Century CPAN Testing: CPANci

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 );}

Page 165: 21st Century CPAN Testing: CPANci

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 );}

Page 166: 21st Century CPAN Testing: CPANci

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 );}

Page 167: 21st Century CPAN Testing: CPANci

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 );}

Page 168: 21st Century CPAN Testing: CPANci

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 );}

Page 169: 21st Century CPAN Testing: CPANci

What does that look like?

We extract the archive in a specific "work" directoryfor each perl.

Then use a temp directory for building and installingdependencies.

foreach my $perl ( @{ $self->perls } ) { my $workdir = catdir $self->home, 'work', $perl, $dist; chdir $workdir;}

Page 170: 21st Century CPAN Testing: CPANci

What does that look like?

We extract the archive in a specific "work" directoryfor each perl.

Then use a temp directory for building and installingdependencies.

foreach my $perl ( @{ $self->perls } ) { my $workdir = catdir $self->home, 'work', $perl, $dist; chdir $workdir;}

Page 171: 21st Century CPAN Testing: CPANci

What does that look like?

We extract the archive in a specific "work" directoryfor each perl.

Then use a temp directory for building and installingdependencies.

foreach my $perl ( @{ $self->perls } ) { my $workdir = catdir $self->home, 'work', $perl, $dist; chdir $workdir;}

Page 172: 21st Century CPAN Testing: CPANci

What does that look like?

We extract the archive in a specific "work" directoryfor each perl.

Then use a temp directory for building and installingdependencies.

foreach my $perl ( @{ $self->perls } ) { my $workdir = catdir $self->home, 'work', $perl, $dist; chdir $workdir;}

Page 173: 21st Century CPAN Testing: CPANci

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 );

Page 174: 21st Century CPAN Testing: CPANci

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 );

Page 175: 21st Century CPAN Testing: CPANci

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 );

Page 176: 21st Century CPAN Testing: CPANci

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 );

Page 177: 21st Century CPAN Testing: CPANci

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 );

Page 178: 21st Century CPAN Testing: CPANci

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 );

Page 179: 21st Century CPAN Testing: CPANci

"deps" : { "log" : [ { "indent" : 0, "type" : "working-on", "line" : "--> Working on .\n" }, { "line" : "Configuring Lingua-EN-NamedEntity-1.92 ... OK\n", "type" : "config", "indent" : 1 }, { "type" : "found-deps", "indent" : 1, "line" : "==> Found dependencies: Lingua::Stem::En, DB_File, LWP::Simple\n" }, { "indent" : 1, "type" : "working-on", "line" : "--> Working on Lingua::Stem::En\n" }, { "indent" : 2, "type" : "fetch", "line" : "Fetching http://www.cpan.org/authors/id/S/SN/SNOWHARE/Lingua-Stem-0.84.tar.gz ... OK\n" },

What does that look like?

Page 180: 21st Century CPAN Testing: CPANci

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 );}

Page 181: 21st Century CPAN Testing: CPANci

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 );}

Page 182: 21st Century CPAN Testing: CPANci

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 );}

Page 183: 21st Century CPAN Testing: CPANci

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 );}

Page 184: 21st Century CPAN Testing: CPANci

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 );}

Page 185: 21st Century CPAN Testing: CPANci

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 );}

Page 186: 21st Century CPAN Testing: CPANci

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 );}

Page 187: 21st Century CPAN Testing: CPANci

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 ) ) : ( ), }; }};

Page 188: 21st Century CPAN Testing: CPANci

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 ) ) : ( ), }; }};

Page 189: 21st Century CPAN Testing: CPANci

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 ) ) : ( ), }; }};

Page 190: 21st Century CPAN Testing: CPANci

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 ) ) : ( ), }; }};

Page 191: 21st Century CPAN Testing: CPANci

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 ) ) : ( ), }; }};

Page 192: 21st Century CPAN Testing: CPANci

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 ) ) : ( ), }; }};

Page 193: 21st Century CPAN Testing: CPANci

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 ) ) : ( ), }; }};

Page 194: 21st Century CPAN Testing: CPANci

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 ) ) : ( ), }; }};

Page 195: 21st Century CPAN Testing: CPANci

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 ) ) : ( ), }; }};

Page 196: 21st Century CPAN Testing: CPANci

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 ) ) : ( ), }; }};

Page 197: 21st Century CPAN Testing: CPANci

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 ) ) : ( ), }; }};

Page 198: 21st Century CPAN Testing: CPANci

What does that look like?

"name" : "t/05depth.t", "lines" : [ { "ok" : true, "text" : "1..12", "type" : "plan" }, { "number" : 1, "ok" : true, "type" : "test", "desc" : "new object", "text" : "ok 1 - new object" }, { "ok" : true, "number" : 2, "desc" : "depth", "type" : "test", "text" : "ok 2 - depth" }, { "desc" : "depth", "text" : "ok 3 - depth", "type" : "test", "number" : 3, "ok" : true }, { "type" : "test", "desc" : "depth", "text" : "ok 4 - depth", "ok" : true, "number" : 4 }, { "number" : 5, "ok" : true, "text" : "ok 5 - depth", "desc" : "depth", "type" : "test" }, { "number" : 6, "ok" : true, "type" : "test", "desc" : "depth", "text" : "ok 6 - depth" },

Page 199: 21st Century CPAN Testing: CPANci

What does that look like?

"name" : "t/05depth.t", "lines" : [ { "ok" : true, "text" : "1..12", "type" : "plan" }, { "number" : 1, "ok" : true, "type" : "test", "desc" : "new object", "text" : "ok 1 - new object" }, { "ok" : true, "number" : 2, "desc" : "depth", "type" : "test", "text" : "ok 2 - depth" }, { "desc" : "depth", "text" : "ok 3 - depth", "type" : "test", "number" : 3, "ok" : true }, { "type" : "test", "desc" : "depth", "text" : "ok 4 - depth", "ok" : true, "number" : 4 }, { "number" : 5, "ok" : true, "text" : "ok 5 - depth", "desc" : "depth", "type" : "test" }, { "number" : 6, "ok" : true, "type" : "test", "desc" : "depth", "text" : "ok 6 - depth" },

Page 200: 21st Century CPAN Testing: CPANci

What does that look like?

"name" : "t/05depth.t", "lines" : [ { "ok" : true, "text" : "1..12", "type" : "plan" }, { "number" : 1, "ok" : true, "type" : "test", "desc" : "new object", "text" : "ok 1 - new object" }, { "ok" : true, "number" : 2, "desc" : "depth", "type" : "test", "text" : "ok 2 - depth" }, { "desc" : "depth", "text" : "ok 3 - depth", "type" : "test", "number" : 3, "ok" : true }, { "type" : "test", "desc" : "depth", "text" : "ok 4 - depth", "ok" : true, "number" : 4 }, { "number" : 5, "ok" : true, "text" : "ok 5 - depth", "desc" : "depth", "type" : "test" }, { "number" : 6, "ok" : true, "type" : "test", "desc" : "depth", "text" : "ok 6 - depth" },

•This is JSON

Page 201: 21st Century CPAN Testing: CPANci

What does that look like?

"name" : "t/05depth.t", "lines" : [ { "ok" : true, "text" : "1..12", "type" : "plan" }, { "number" : 1, "ok" : true, "type" : "test", "desc" : "new object", "text" : "ok 1 - new object" }, { "ok" : true, "number" : 2, "desc" : "depth", "type" : "test", "text" : "ok 2 - depth" }, { "desc" : "depth", "text" : "ok 3 - depth", "type" : "test", "number" : 3, "ok" : true }, { "type" : "test", "desc" : "depth", "text" : "ok 4 - depth", "ok" : true, "number" : 4 }, { "number" : 5, "ok" : true, "text" : "ok 5 - depth", "desc" : "depth", "type" : "test" }, { "number" : 6, "ok" : true, "type" : "test", "desc" : "depth", "text" : "ok 6 - depth" },

•This is JSON•Stored in MongoDB

Page 202: 21st Century CPAN Testing: CPANci

What does that look like?

"name" : "t/05depth.t", "lines" : [ { "ok" : true, "text" : "1..12", "type" : "plan" }, { "number" : 1, "ok" : true, "type" : "test", "desc" : "new object", "text" : "ok 1 - new object" }, { "ok" : true, "number" : 2, "desc" : "depth", "type" : "test", "text" : "ok 2 - depth" }, { "desc" : "depth", "text" : "ok 3 - depth", "type" : "test", "number" : 3, "ok" : true }, { "type" : "test", "desc" : "depth", "text" : "ok 4 - depth", "ok" : true, "number" : 4 }, { "number" : 5, "ok" : true, "text" : "ok 5 - depth", "desc" : "depth", "type" : "test" }, { "number" : 6, "ok" : true, "type" : "test", "desc" : "depth", "text" : "ok 6 - depth" },

•This is JSON•Stored in MongoDB•But it's also TAP!

Page 203: 21st Century CPAN Testing: CPANci

What does that mean?

Page 204: 21st Century CPAN Testing: CPANci

Beautiful Tables!

Page 205: 21st Century CPAN Testing: CPANci

Final Thoughts

Page 206: 21st Century CPAN Testing: CPANci

Final Thoughts

•Play with new toys.

Page 207: 21st Century CPAN Testing: CPANci

Final Thoughts

•Play with new toys.•Think before you code.

Page 208: 21st Century CPAN Testing: CPANci

Final Thoughts

•Play with new toys.•Think before you code.•Throw stuff away.

Page 209: 21st Century CPAN Testing: CPANci

Final Thoughts

•Play with new toys.•Think before you code.•Throw stuff away.•Have bad ideas.

Page 210: 21st Century CPAN Testing: CPANci

Final Thoughts

•Play with new toys.•Think before you code.•Throw stuff away.•Have bad ideas.•Ask stupid questions.

Page 211: 21st Century CPAN Testing: CPANci

Final Thoughts

•Play with new toys.•Think before you code.•Throw stuff away.•Have bad ideas.•Ask stupid questions.•Have fun.

Page 212: 21st Century CPAN Testing: CPANci

!