SlideShare a Scribd company logo
1 of 48
Download to read offline
The $path to Knowlege:
What little it takes to test perl.
Steven Lembark
Workhorse Computing
lembark@wrkhors.com
Everyone wants to leave a legacy.
Makes sense: Leave your mark on history.
Everyone wants to leave a legacy.
Makes sense: Leave your mark on history.
What if your mark is history?
It never changes.
It never adapts.
Forever frozen in the wastelands of 5.8.
Growing beyond legacy.
Any number of companies have legacy Perl code.
Any number of reasons it isn’t upgraded.
Then you decide to upgrade, get current.
Now what?
First step: Triage
Obvious questions:
What’s working?
What’s broken?
What’s next?
First step: Triage
Obvious questions:
What’s working?
What’s broken?
What’s next?
A: Let’s find out.
Example
I’ve worked for multiple clients with v5.8 code.
Then they wanted to upgrade.
Say to 5.2X or later.
Undo a few decades of technical debt.
Only takes a few weeks, right?
So what? You test the code?
Next step is testing lots of files.
Repeating the same tests, over and over.
Rule 1: Avoid Red Flags.
Don’t copy, cut, or paste.
Use Lazyness.
Perl Somalier
<https://www.perl.com/pub/2000/04/raceinfo.html/>
The Repair Shop has aged well:
Nice bouquet, pleasant aftertaste.
All the things that make cleaning up code pleasing.
Step 1: use perl.
#!/usr/bin/env perl
not /usr/bin/perl.
Then check your path.
Step 2: Find the perly files
find lib -type f -name ‘*pm’;
Skip shell programs:
find bin scripts utils -type f |
xargs file |
grep ‘Perl’ |
cut -d’:’ -f1 ;
OK: unit test the files
OK, so you copy a red flag... er... template for each...
Define a datafile?
Write the YAML file from hell?
Create JSON from worse?
Nope.
Start with a path.
Q: What do we need in order to unit test one module?
A: Its path.
/my/sandbox/XYX/lib/Foo/Bar.pm
Start with a path.
Q: What do we need in order to unit test one module?
A: Its path.
/my/sandbox/XYX/lib/Foo/Bar.pm
Encoded in a symlink:
./t/01-pm/~my~sandbox~XYZ~lib~Foo~Bar.pm.t
Start with a path.
Q: What do we need in order to unit test one module?
A: Its path.
/my/sandbox/XYX/lib/Foo/Bar.pm
Along with its package:
./t/01-pm/~my~sandbox~XYZ~lib~~Foo~Bar.pm.t
Start with a path.
Q: What do we need in order to unit test one module?
A: Its path.
/my/sandbox/XYX/lib/Foo/Bar.pm
Along with its package:
./t/01-pm/~my~sandbox~XYZ~lib~~Foo~Bar.pm.t
~Foo~Bar
Start with a path.
Q: What do we need in order to unit test one module?
A: Its path.
/my/sandbox/XYX/lib/Foo/Bar.pm
Along with its package:
./t/01-pm/~my~sandbox~XYZ~lib~~Foo~Bar.pm.t
Foo::Bar
Start with a path.
use Test::More;
use File::Basename;
my $base0 = basename $0;
my $sep = substr $base0, 0, 1;
my $path = join '/' => split m{[$sep]}, $base0;
my ($pkg) = $path =~ m{// (.+?) [.]pm$}x;
my $pkg =~ s{W}{::}g;
require_ok $path
or skip "Failed require", 1;
can_ok $pkg, 'VERSION'
or skip "Missing packge: '$pkg' ($path)";
Given a path and a packge...
What else would you want to test?
How about exports?
Validating @EXPORT & @EXPORT_OK
Basic problem: Exporting what isn’t.
Undefined values in @EXPORT or @EXPORT_OK.
Botched names.
Validating @EXPORT & @EXPORT_OK
Both can easily be checked.
Symbol is your friend.
qualify_to_ref is your buddy.
Validating @EXPORT & @EXPORT_OK
Starting with $path and $pkg:
Require the path.
Check for @EXPORT, @EXPORT_OK.
Walk down whichever is defined.
Check that the contents are defined.
Validating @EXPORT & @EXPORT_OK
# basic sanity checks: configured for exporting.
require_ok $path or skip “oops...”, 1;
isa_ok $pkg, ‘Exporter’ or skip “$pkg is not Exporter”;
can_ok $path -> 'import'
or do
{
diag “Botched $pkg: Exporter lacks ‘import’”;
skip “$pkg cannot ‘import’”
};
# hold off calling import until we have some values.
# maybe a diag for can_ok
Validating @EXPORT & @EXPORT_OK
# second step: check the contents of EXPORT & _OK
# require_ok doesn’t call import: need it for @EXPORT.
for my $exp ( qw( EXPORT EXPORT_OK ) )
{
my $ref = qualify_to_ref $exp => $pkg;
my $found = *{$ref}{ARRAY} or next;
note "Validate: $pkg $expn", explain $found;
my @namz = @$found
or skip "$pkg has empty '$exp'";
$pkg->import( @namz );
Validating @EXPORT & @EXPORT_OK
for my $name ( @namz )
{
my $sigil
= $name =~ m{^w} ? '&' : substr $name, 0, 1, '' ;
if( ‘&’ eq $sigil )
{
# anything exported should exist in both places.
can_ok $pkg, $name;
can_ok __PACKAGE__, $name;
}
else
...
Validating @EXPORT & @EXPORT_OK
...
{
state $sig2type = [qw( @ ARRAY % HASH $ SCLALAR ...) ];
my $type = $sigil2type{ $sigil };
my $src = qualify_to_ref $name, $pkg;
my $dst = qualify_to_ref $name, __PACKGE__;
my $src_v = *{ $ref }{ $type }
or do { diag “$pkg lacks ‘$name’”; next };
my $dst_v = *{ $dst }{ $type };
is_deeply $src_v, $dst_v, “$name exported from $pkg”;
}
}
Ever get sick of typing “perl -wc”?
Lazyness is a virtue: Let perl type it for you.
All you need is the path, perl, and a version.
Ever get sick of typing “perl -wc”?
chomp ( my $perl = qx{ which perl } );
my $run_d = dirname $0;
my $path = ( basename $0, '.t' ) =~ tr{~}{/}r;
my $base = basename $path;
SKIP:
{
-e $perl or skip "Non-existant: 'perl'";
-x $perl or skip "Non-executable: '$perl'";
-e $path or skip "Non-existant: '$path'";
-r $path or skip "Non-readable: '$path'";
-s $path or skip "Zero-sized: '$path'";
# at this point the test is run-able
Ever get sick of typing “perl -wk”?
chomp ( my $perl = qx{ which perl } );
# $^V isn’t perfect, but it’s a start.
my $input = "(echo ‘use $^V’; cat $path)";
my $cmd = "$input | perl -wc -";
my $out = qx{ $cmd 2>&1 };
my $exit = $?;
ok 0 == $exit, "Compile: '$base'";
$out eq "- Syntax OKn"
or
diag "nPerl diagnostic: '$path'n$outn";
}
Ever get sick of typing “perl -wk”?
chomp ( my $perl = qx{ which perl } );
# $^V isn’t perfect, but it’s a start.
my $input = "(echo ‘use $^V’; cat $path)";
my $cmd = "$input | perl -wc -";
my $out = qx{ $cmd 2>&1 };
my $exit = $?;
ok 0 == $exit, "Compile: '$base'";
$out eq "- Syntax OKn"
or
diag "nPerl diagnostic: '$path'n$outn";
}
Prove is lazier than perl -wc for each file.
Ouptut is quite paste-able:
GitLab issue:
~~~perl
<paste test output here>
~~~
Cleaning up Exports
Life begings with Globals.pm
@EXPORT qw( … );
~1500 entries.
Can’t delete any: Nobody knows what’s used.
Gotta maintain them all.
Cleaning up Exports
Life begings with Globals.pm
@EXPORT qw( … );
~1500 entries.
Can’t delete any: Nobody knows what’s used.
Gotta maintain them all.
Not...
Cleaning up Exports
Tests give us @EXPORT* & diagnostics.
Step 1: @EXPORT_OK
Yes, this breaks all of the code.
Result: We know what is missing.
Cleaning up Exports
Step 2: Diagnostics list undefined variables.
Grep them out.
Generate “use Global qw( … )” lines.
Updates via perl -i -p.
Result: We know what is used.
Cleaning up Exports
Step 3: Start removing unused exports.
Look at what we added.
Comment the rest.
Test diag’s tell us when we go too far.
And when to stop.
Testing with Jenkins
As always: There’s more than one way.
One simple fix:
./devops/Jenkinsfile
./devops/run-tests
Testing with Jenkins
stage("Runtime Env")
{
steps
{
sh "uname -a"
sh "hostname"
sh "pwd -L"
sh "pwd -P"
sh "set"
}
}
Testing with Jenkins
stage("Run Tests")
{
environment
{
path = “${env.WORKSPACE_TMP + ‘/prove’}”
}
steps
{
sh "git submodule init"
sh "git submodule update"
sh "./devops/run-tests"
}
}
Testing with Jenkins
stage("Run Tests")
{
environment
{
path = “${env.WORKSPACE_TMP + ‘/prove’}”
}
steps
{
sh "git submodule init"
sh "git submodule update"
sh "./devops/run-tests"
}
}
Testing with Jenkins
#!/bin/bash -x
perl -V;
prove -V;
echo “Ouput: ‘$path’”;
cmd=”prove -r --jobs=4 --state=save --statefile=$path t”;
cd $(dirname $0)/../..;
./t/bin/install-test-symlinks;
$cmd 2>&1 | tee "$path.out";
How do we know which files to test?
Simple: Ask
*.pm files are easy.
Find #!perl files with
find lib scripts utils progs apps -type f |
xargs file |
grep 'Perl' |
cut -d':' -f1 |
xargs ./t/bin/install-symlinks $dir ;
Bits of Jenins
Put site_perl into a git submodule.
Advanced Options for Jenkins: Submodules.
Allows shallow copy & recurse submodules.
Maintain as a seprate repo:
cpanm --local-lib=. --self-contained ... ;
git add .;
git commit -m’update CPAN’;
Bits of Jenins
environment
{
PERL5LIB = "$WORKSPACE/site_perl/lib/perl5"
TEMPDIR = "$WORKSPACE_TMP"
}
Test & Package Perl with Jenkins
Distribute your own cpan via ./site_perl.
Nice place for a submodule.
Catch: How do you find it?
Bits of Jenins
environment
{
PERL5LIB = "$WORKSPACE/site_perl/lib/perl5"
TEMPDIR = "$WORKSPACE_TMP"
}
Test & Package Perl with Jenkins
Distribute your own cpan via ./site_perl.
Nice place for a submodule.
Catch: How do you find it?
Bits of Jenins
environment
{
PERL5LIB = "$WORKSPACE/site_perl/lib/perl5"
TEMPDIR = "$WORKSPACE_TMP"
}
Test & Package Perl with Jenkins
Tee results or store ‘artifacts’.
Net result: Paths can tell you a lot.
Easy to acquire.
Easy to use: basenames & require_ok.
Explore with Symbol.
Net result: Paths can tell you a lot.
Jenkins’ plays nicely with Perl.
Distribute tests from git.
Including CPAN modules.

More Related Content

What's hot

BSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationBSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationWorkhorse Computing
 
Melhorando sua API com DSLs
Melhorando sua API com DSLsMelhorando sua API com DSLs
Melhorando sua API com DSLsAugusto Pascutti
 
Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6Workhorse Computing
 
I, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 OverlordsI, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 Overlordsheumann
 
Utility Modules That You Should Know About
Utility Modules That You Should Know AboutUtility Modules That You Should Know About
Utility Modules That You Should Know Aboutjoshua.mcadams
 
Barely Legal Xxx Perl Presentation
Barely Legal Xxx Perl PresentationBarely Legal Xxx Perl Presentation
Barely Legal Xxx Perl PresentationAttila Balazs
 
Perl web frameworks
Perl web frameworksPerl web frameworks
Perl web frameworksdiego_k
 
Webrtc mojo
Webrtc mojoWebrtc mojo
Webrtc mojobpmedley
 
Perforce Object and Record Model
Perforce Object and Record Model  Perforce Object and Record Model
Perforce Object and Record Model Perforce
 
Smolder @Silex
Smolder @SilexSmolder @Silex
Smolder @SilexJeen Lee
 

What's hot (20)

Get your teeth into Plack
Get your teeth into PlackGet your teeth into Plack
Get your teeth into Plack
 
BSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationBSDM with BASH: Command Interpolation
BSDM with BASH: Command Interpolation
 
Memory Manglement in Raku
Memory Manglement in RakuMemory Manglement in Raku
Memory Manglement in Raku
 
Getting Testy With Perl6
Getting Testy With Perl6Getting Testy With Perl6
Getting Testy With Perl6
 
Unit Testing Lots of Perl
Unit Testing Lots of PerlUnit Testing Lots of Perl
Unit Testing Lots of Perl
 
Getting testy with Perl
Getting testy with PerlGetting testy with Perl
Getting testy with Perl
 
Effective Benchmarks
Effective BenchmarksEffective Benchmarks
Effective Benchmarks
 
Melhorando sua API com DSLs
Melhorando sua API com DSLsMelhorando sua API com DSLs
Melhorando sua API com DSLs
 
Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6
 
I, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 OverlordsI, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 Overlords
 
Utility Modules That You Should Know About
Utility Modules That You Should Know AboutUtility Modules That You Should Know About
Utility Modules That You Should Know About
 
Perl6 in-production
Perl6 in-productionPerl6 in-production
Perl6 in-production
 
Perl basics for Pentesters
Perl basics for PentestersPerl basics for Pentesters
Perl basics for Pentesters
 
Barely Legal Xxx Perl Presentation
Barely Legal Xxx Perl PresentationBarely Legal Xxx Perl Presentation
Barely Legal Xxx Perl Presentation
 
Perl web frameworks
Perl web frameworksPerl web frameworks
Perl web frameworks
 
Webrtc mojo
Webrtc mojoWebrtc mojo
Webrtc mojo
 
Perl6 grammars
Perl6 grammarsPerl6 grammars
Perl6 grammars
 
Troubleshooting Puppet
Troubleshooting PuppetTroubleshooting Puppet
Troubleshooting Puppet
 
Perforce Object and Record Model
Perforce Object and Record Model  Perforce Object and Record Model
Perforce Object and Record Model
 
Smolder @Silex
Smolder @SilexSmolder @Silex
Smolder @Silex
 

Similar to The $path to knowledge: What little it take to unit-test Perl.

Good Evils In Perl
Good Evils In PerlGood Evils In Perl
Good Evils In PerlKang-min Liu
 
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...Rodolfo Carvalho
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl TechniquesDave Cross
 
Testing Code and Assuring Quality
Testing Code and Assuring QualityTesting Code and Assuring Quality
Testing Code and Assuring QualityKent Cowgill
 
Perl Sucks - and what to do about it
Perl Sucks - and what to do about itPerl Sucks - and what to do about it
Perl Sucks - and what to do about it2shortplanks
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Kang-min Liu
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everythingnoelrap
 
A Whirlwind Tour of Test::Class
A Whirlwind Tour of Test::ClassA Whirlwind Tour of Test::Class
A Whirlwind Tour of Test::ClassCurtis Poe
 
How to Vim - for beginners
How to Vim - for beginnersHow to Vim - for beginners
How to Vim - for beginnersMarcin Rogacki
 
10 tips for making Bash a sane programming language
10 tips for making Bash a sane programming language10 tips for making Bash a sane programming language
10 tips for making Bash a sane programming languageYaroslav Tkachenko
 
How to develop modern web application framework
How to develop modern web application frameworkHow to develop modern web application framework
How to develop modern web application frameworktechmemo
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl TechniquesDave Cross
 

Similar to The $path to knowledge: What little it take to unit-test Perl. (20)

Good Evils In Perl
Good Evils In PerlGood Evils In Perl
Good Evils In Perl
 
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
 
Testing Code and Assuring Quality
Testing Code and Assuring QualityTesting Code and Assuring Quality
Testing Code and Assuring Quality
 
Perl Sucks - and what to do about it
Perl Sucks - and what to do about itPerl Sucks - and what to do about it
Perl Sucks - and what to do about it
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
 
Perl Moderno
Perl ModernoPerl Moderno
Perl Moderno
 
Cleancode
CleancodeCleancode
Cleancode
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
IntroTestMore
IntroTestMoreIntroTestMore
IntroTestMore
 
IntroTestMore
IntroTestMoreIntroTestMore
IntroTestMore
 
A Whirlwind Tour of Test::Class
A Whirlwind Tour of Test::ClassA Whirlwind Tour of Test::Class
A Whirlwind Tour of Test::Class
 
How to Vim - for beginners
How to Vim - for beginnersHow to Vim - for beginners
How to Vim - for beginners
 
10 tips for making Bash a sane programming language
10 tips for making Bash a sane programming language10 tips for making Bash a sane programming language
10 tips for making Bash a sane programming language
 
Modern Perl
Modern PerlModern Perl
Modern Perl
 
How to develop modern web application framework
How to develop modern web application frameworkHow to develop modern web application framework
How to develop modern web application framework
 
PHP Unit Testing
PHP Unit TestingPHP Unit Testing
PHP Unit Testing
 
Laravel Day / Deploy
Laravel Day / DeployLaravel Day / Deploy
Laravel Day / Deploy
 
Git::Hooks
Git::HooksGit::Hooks
Git::Hooks
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
 

More from Workhorse Computing

Wheels we didn't re-invent: Perl's Utility Modules
Wheels we didn't re-invent: Perl's Utility ModulesWheels we didn't re-invent: Perl's Utility Modules
Wheels we didn't re-invent: Perl's Utility ModulesWorkhorse Computing
 
Paranormal statistics: Counting What Doesn't Add Up
Paranormal statistics: Counting What Doesn't Add UpParanormal statistics: Counting What Doesn't Add Up
Paranormal statistics: Counting What Doesn't Add UpWorkhorse Computing
 
Generating & Querying Calendar Tables in Posgresql
Generating & Querying Calendar Tables in PosgresqlGenerating & Querying Calendar Tables in Posgresql
Generating & Querying Calendar Tables in PosgresqlWorkhorse Computing
 
The W-curve and its application.
The W-curve and its application.The W-curve and its application.
The W-curve and its application.Workhorse Computing
 
Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.Workhorse Computing
 
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6Workhorse Computing
 
Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.Workhorse Computing
 
Selenium sandwich-3: Being where you aren't.
Selenium sandwich-3: Being where you aren't.Selenium sandwich-3: Being where you aren't.
Selenium sandwich-3: Being where you aren't.Workhorse Computing
 
Selenium Sandwich Part 1: Data driven Selenium
Selenium Sandwich Part 1: Data driven Selenium Selenium Sandwich Part 1: Data driven Selenium
Selenium Sandwich Part 1: Data driven Selenium Workhorse Computing
 

More from Workhorse Computing (18)

Wheels we didn't re-invent: Perl's Utility Modules
Wheels we didn't re-invent: Perl's Utility ModulesWheels we didn't re-invent: Perl's Utility Modules
Wheels we didn't re-invent: Perl's Utility Modules
 
mro-every.pdf
mro-every.pdfmro-every.pdf
mro-every.pdf
 
Paranormal statistics: Counting What Doesn't Add Up
Paranormal statistics: Counting What Doesn't Add UpParanormal statistics: Counting What Doesn't Add Up
Paranormal statistics: Counting What Doesn't Add Up
 
Generating & Querying Calendar Tables in Posgresql
Generating & Querying Calendar Tables in PosgresqlGenerating & Querying Calendar Tables in Posgresql
Generating & Querying Calendar Tables in Posgresql
 
The W-curve and its application.
The W-curve and its application.The W-curve and its application.
The W-curve and its application.
 
Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.
 
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
 
Neatly folding-a-tree
Neatly folding-a-treeNeatly folding-a-tree
Neatly folding-a-tree
 
Light my-fuse
Light my-fuseLight my-fuse
Light my-fuse
 
Paranormal stats
Paranormal statsParanormal stats
Paranormal stats
 
Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.
 
Putting some "logic" in LVM.
Putting some "logic" in LVM.Putting some "logic" in LVM.
Putting some "logic" in LVM.
 
Selenium sandwich-3: Being where you aren't.
Selenium sandwich-3: Being where you aren't.Selenium sandwich-3: Being where you aren't.
Selenium sandwich-3: Being where you aren't.
 
Selenium sandwich-2
Selenium sandwich-2Selenium sandwich-2
Selenium sandwich-2
 
Selenium Sandwich Part 1: Data driven Selenium
Selenium Sandwich Part 1: Data driven Selenium Selenium Sandwich Part 1: Data driven Selenium
Selenium Sandwich Part 1: Data driven Selenium
 
Docker perl build
Docker perl buildDocker perl build
Docker perl build
 
Designing net-aws-glacier
Designing net-aws-glacierDesigning net-aws-glacier
Designing net-aws-glacier
 
Lies, Damn Lies, and Benchmarks
Lies, Damn Lies, and BenchmarksLies, Damn Lies, and Benchmarks
Lies, Damn Lies, and Benchmarks
 

Recently uploaded

Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraDeakin University
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 

Recently uploaded (20)

Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning era
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 

The $path to knowledge: What little it take to unit-test Perl.

  • 1. The $path to Knowlege: What little it takes to test perl. Steven Lembark Workhorse Computing lembark@wrkhors.com
  • 2. Everyone wants to leave a legacy. Makes sense: Leave your mark on history.
  • 3. Everyone wants to leave a legacy. Makes sense: Leave your mark on history. What if your mark is history? It never changes. It never adapts. Forever frozen in the wastelands of 5.8.
  • 4. Growing beyond legacy. Any number of companies have legacy Perl code. Any number of reasons it isn’t upgraded. Then you decide to upgrade, get current. Now what?
  • 5. First step: Triage Obvious questions: What’s working? What’s broken? What’s next?
  • 6. First step: Triage Obvious questions: What’s working? What’s broken? What’s next? A: Let’s find out.
  • 7. Example I’ve worked for multiple clients with v5.8 code. Then they wanted to upgrade. Say to 5.2X or later. Undo a few decades of technical debt. Only takes a few weeks, right?
  • 8. So what? You test the code? Next step is testing lots of files. Repeating the same tests, over and over. Rule 1: Avoid Red Flags. Don’t copy, cut, or paste. Use Lazyness.
  • 9. Perl Somalier <https://www.perl.com/pub/2000/04/raceinfo.html/> The Repair Shop has aged well: Nice bouquet, pleasant aftertaste. All the things that make cleaning up code pleasing.
  • 10. Step 1: use perl. #!/usr/bin/env perl not /usr/bin/perl. Then check your path.
  • 11. Step 2: Find the perly files find lib -type f -name ‘*pm’; Skip shell programs: find bin scripts utils -type f | xargs file | grep ‘Perl’ | cut -d’:’ -f1 ;
  • 12. OK: unit test the files OK, so you copy a red flag... er... template for each... Define a datafile? Write the YAML file from hell? Create JSON from worse? Nope.
  • 13. Start with a path. Q: What do we need in order to unit test one module? A: Its path. /my/sandbox/XYX/lib/Foo/Bar.pm
  • 14. Start with a path. Q: What do we need in order to unit test one module? A: Its path. /my/sandbox/XYX/lib/Foo/Bar.pm Encoded in a symlink: ./t/01-pm/~my~sandbox~XYZ~lib~Foo~Bar.pm.t
  • 15. Start with a path. Q: What do we need in order to unit test one module? A: Its path. /my/sandbox/XYX/lib/Foo/Bar.pm Along with its package: ./t/01-pm/~my~sandbox~XYZ~lib~~Foo~Bar.pm.t
  • 16. Start with a path. Q: What do we need in order to unit test one module? A: Its path. /my/sandbox/XYX/lib/Foo/Bar.pm Along with its package: ./t/01-pm/~my~sandbox~XYZ~lib~~Foo~Bar.pm.t ~Foo~Bar
  • 17. Start with a path. Q: What do we need in order to unit test one module? A: Its path. /my/sandbox/XYX/lib/Foo/Bar.pm Along with its package: ./t/01-pm/~my~sandbox~XYZ~lib~~Foo~Bar.pm.t Foo::Bar
  • 18. Start with a path. use Test::More; use File::Basename; my $base0 = basename $0; my $sep = substr $base0, 0, 1; my $path = join '/' => split m{[$sep]}, $base0; my ($pkg) = $path =~ m{// (.+?) [.]pm$}x; my $pkg =~ s{W}{::}g; require_ok $path or skip "Failed require", 1; can_ok $pkg, 'VERSION' or skip "Missing packge: '$pkg' ($path)";
  • 19. Given a path and a packge... What else would you want to test? How about exports?
  • 20. Validating @EXPORT & @EXPORT_OK Basic problem: Exporting what isn’t. Undefined values in @EXPORT or @EXPORT_OK. Botched names.
  • 21. Validating @EXPORT & @EXPORT_OK Both can easily be checked. Symbol is your friend. qualify_to_ref is your buddy.
  • 22. Validating @EXPORT & @EXPORT_OK Starting with $path and $pkg: Require the path. Check for @EXPORT, @EXPORT_OK. Walk down whichever is defined. Check that the contents are defined.
  • 23. Validating @EXPORT & @EXPORT_OK # basic sanity checks: configured for exporting. require_ok $path or skip “oops...”, 1; isa_ok $pkg, ‘Exporter’ or skip “$pkg is not Exporter”; can_ok $path -> 'import' or do { diag “Botched $pkg: Exporter lacks ‘import’”; skip “$pkg cannot ‘import’” }; # hold off calling import until we have some values. # maybe a diag for can_ok
  • 24. Validating @EXPORT & @EXPORT_OK # second step: check the contents of EXPORT & _OK # require_ok doesn’t call import: need it for @EXPORT. for my $exp ( qw( EXPORT EXPORT_OK ) ) { my $ref = qualify_to_ref $exp => $pkg; my $found = *{$ref}{ARRAY} or next; note "Validate: $pkg $expn", explain $found; my @namz = @$found or skip "$pkg has empty '$exp'"; $pkg->import( @namz );
  • 25. Validating @EXPORT & @EXPORT_OK for my $name ( @namz ) { my $sigil = $name =~ m{^w} ? '&' : substr $name, 0, 1, '' ; if( ‘&’ eq $sigil ) { # anything exported should exist in both places. can_ok $pkg, $name; can_ok __PACKAGE__, $name; } else ...
  • 26. Validating @EXPORT & @EXPORT_OK ... { state $sig2type = [qw( @ ARRAY % HASH $ SCLALAR ...) ]; my $type = $sigil2type{ $sigil }; my $src = qualify_to_ref $name, $pkg; my $dst = qualify_to_ref $name, __PACKGE__; my $src_v = *{ $ref }{ $type } or do { diag “$pkg lacks ‘$name’”; next }; my $dst_v = *{ $dst }{ $type }; is_deeply $src_v, $dst_v, “$name exported from $pkg”; } }
  • 27. Ever get sick of typing “perl -wc”? Lazyness is a virtue: Let perl type it for you. All you need is the path, perl, and a version.
  • 28. Ever get sick of typing “perl -wc”? chomp ( my $perl = qx{ which perl } ); my $run_d = dirname $0; my $path = ( basename $0, '.t' ) =~ tr{~}{/}r; my $base = basename $path; SKIP: { -e $perl or skip "Non-existant: 'perl'"; -x $perl or skip "Non-executable: '$perl'"; -e $path or skip "Non-existant: '$path'"; -r $path or skip "Non-readable: '$path'"; -s $path or skip "Zero-sized: '$path'"; # at this point the test is run-able
  • 29. Ever get sick of typing “perl -wk”? chomp ( my $perl = qx{ which perl } ); # $^V isn’t perfect, but it’s a start. my $input = "(echo ‘use $^V’; cat $path)"; my $cmd = "$input | perl -wc -"; my $out = qx{ $cmd 2>&1 }; my $exit = $?; ok 0 == $exit, "Compile: '$base'"; $out eq "- Syntax OKn" or diag "nPerl diagnostic: '$path'n$outn"; }
  • 30. Ever get sick of typing “perl -wk”? chomp ( my $perl = qx{ which perl } ); # $^V isn’t perfect, but it’s a start. my $input = "(echo ‘use $^V’; cat $path)"; my $cmd = "$input | perl -wc -"; my $out = qx{ $cmd 2>&1 }; my $exit = $?; ok 0 == $exit, "Compile: '$base'"; $out eq "- Syntax OKn" or diag "nPerl diagnostic: '$path'n$outn"; }
  • 31. Prove is lazier than perl -wc for each file. Ouptut is quite paste-able: GitLab issue: ~~~perl <paste test output here> ~~~
  • 32. Cleaning up Exports Life begings with Globals.pm @EXPORT qw( … ); ~1500 entries. Can’t delete any: Nobody knows what’s used. Gotta maintain them all.
  • 33. Cleaning up Exports Life begings with Globals.pm @EXPORT qw( … ); ~1500 entries. Can’t delete any: Nobody knows what’s used. Gotta maintain them all. Not...
  • 34. Cleaning up Exports Tests give us @EXPORT* & diagnostics. Step 1: @EXPORT_OK Yes, this breaks all of the code. Result: We know what is missing.
  • 35. Cleaning up Exports Step 2: Diagnostics list undefined variables. Grep them out. Generate “use Global qw( … )” lines. Updates via perl -i -p. Result: We know what is used.
  • 36. Cleaning up Exports Step 3: Start removing unused exports. Look at what we added. Comment the rest. Test diag’s tell us when we go too far. And when to stop.
  • 37. Testing with Jenkins As always: There’s more than one way. One simple fix: ./devops/Jenkinsfile ./devops/run-tests
  • 38. Testing with Jenkins stage("Runtime Env") { steps { sh "uname -a" sh "hostname" sh "pwd -L" sh "pwd -P" sh "set" } }
  • 39. Testing with Jenkins stage("Run Tests") { environment { path = “${env.WORKSPACE_TMP + ‘/prove’}” } steps { sh "git submodule init" sh "git submodule update" sh "./devops/run-tests" } }
  • 40. Testing with Jenkins stage("Run Tests") { environment { path = “${env.WORKSPACE_TMP + ‘/prove’}” } steps { sh "git submodule init" sh "git submodule update" sh "./devops/run-tests" } }
  • 41. Testing with Jenkins #!/bin/bash -x perl -V; prove -V; echo “Ouput: ‘$path’”; cmd=”prove -r --jobs=4 --state=save --statefile=$path t”; cd $(dirname $0)/../..; ./t/bin/install-test-symlinks; $cmd 2>&1 | tee "$path.out";
  • 42. How do we know which files to test? Simple: Ask *.pm files are easy. Find #!perl files with find lib scripts utils progs apps -type f | xargs file | grep 'Perl' | cut -d':' -f1 | xargs ./t/bin/install-symlinks $dir ;
  • 43. Bits of Jenins Put site_perl into a git submodule. Advanced Options for Jenkins: Submodules. Allows shallow copy & recurse submodules. Maintain as a seprate repo: cpanm --local-lib=. --self-contained ... ; git add .; git commit -m’update CPAN’;
  • 44. Bits of Jenins environment { PERL5LIB = "$WORKSPACE/site_perl/lib/perl5" TEMPDIR = "$WORKSPACE_TMP" } Test & Package Perl with Jenkins Distribute your own cpan via ./site_perl. Nice place for a submodule. Catch: How do you find it?
  • 45. Bits of Jenins environment { PERL5LIB = "$WORKSPACE/site_perl/lib/perl5" TEMPDIR = "$WORKSPACE_TMP" } Test & Package Perl with Jenkins Distribute your own cpan via ./site_perl. Nice place for a submodule. Catch: How do you find it?
  • 46. Bits of Jenins environment { PERL5LIB = "$WORKSPACE/site_perl/lib/perl5" TEMPDIR = "$WORKSPACE_TMP" } Test & Package Perl with Jenkins Tee results or store ‘artifacts’.
  • 47. Net result: Paths can tell you a lot. Easy to acquire. Easy to use: basenames & require_ok. Explore with Symbol.
  • 48. Net result: Paths can tell you a lot. Jenkins’ plays nicely with Perl. Distribute tests from git. Including CPAN modules.