Initial Commit

This commit is contained in:
Riley Schneider
2025-12-03 16:38:10 +01:00
parent c5e26bf594
commit b732d8d4b5
17680 changed files with 5977495 additions and 2 deletions

View File

@@ -0,0 +1,78 @@
package Test2::Manual::Anatomy::API;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy::API - Internals documentation for the API.
=head1 DESCRIPTION
This document covers some of the internals of L<Test2::API>.
=head1 IMPLEMENTATION DETAILS
=head2 Test2::API
L<Test2::API> provides a functional interface to any test2 global state. This
API should be preserved regardless of internal details of how and where the
global state is stored.
This module itself does not store any state (with a few minor exceptions) but
instead relies on L<Test2::API::Instance> to store state. This module is really
intended to be the layer between the consumer and the implementation details.
Ideally the implementation details can change any way they like, and this
module can be updated to use the new details without breaking anything.
=head2 Test2::API::Instance
L<Test2::API::Instance> is where the global state is actually managed. This is
an implementation detail, and should not be relied upon. It is entirely
possible that L<Test2::API::Instance> could be removed completely, or changed
in incompatible ways. Really these details are free to change so long as
L<Test2::API> is not broken.
L<Test2::API::Instance> is fairly well documented, so no additionally
documentation is needed for this manual page.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,114 @@
package Test2::Manual::Anatomy::Context;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy::Context - Internals documentation for the Context
objects.
=head1 DESCRIPTION
This document explains how the L<Test2::API::Context> object works.
=head1 WHAT IS THE CONTEXT OBJECT?
The context object is one of the key components of Test2, and makes many
features possible that would otherwise be impossible. Every test tool starts by
getting a context, and ends by releasing the context. A test tool does all its
work between getting and releasing the context. The context instance is the
primary interface for sending events to the Test2 stack. Finally the context
system is responsible for tracking what file and line number a tool operates
on, which is critical for debugging.
=head2 PRIMARY INTERFACE FOR TEST TOOLS
Nearly every Test2 based tool should start by calling C<$ctx =
Test2::API::context()> in order to get a context object, and should end by
calling C<< $ctx->release() >>. Once a tool has its context object it can call
methods on the object to send events or have other effects. Nearly everything a
test tool needs to do should be done through the context object.
=head2 TRACK FILE AND LINE NUMBERS FOR ERROR REPORTING
When you call C<Test2::API::Context> a new context object will be returned. If
there is already a context object in effect (from a different point in the
stack) you will get a clone of the existing one. If there is not already a
current context then a completely new one will be generated. When a new context
is generated Test2 will determine the file name and line number for your test
code, these will be used when reporting any failures.
Typically the file and line number will be determined using C<caller()> to look
at your tools caller. The C<$Test::Builder::Level> will be respected if
detected, but is discouraged in favor of just using context objects at every
level.
When calling C<Test2::API::Context()> you can specify the
C<< level => $count >> arguments if you need to look at a deeper caller.
=head2 PRESERVE $?, $!, $^E AND $@
When you call C<Test2::API::context()> the current values of C<$?>, C<$!>,
C<$^E>, and C<$@> are stored in the context object itself. Whenever the context
is released the original values of these variables will be restored. This
protects the variables from any side effects caused by testing tools.
=head2 FINALIZE THE API STATE
L<Test2::API> works via a hidden singleton instance of L<Test2::API::Instance>.
The singleton has some state that is not set in stone until the last possible
minute. The last possible minute happens to be the first time a context is
acquired. State includes IPC instance, Formatter class, Root PID, etc.
=head2 FIND/CREATE THE CURRENT/ROOT HUB
L<Test2> has a stack of hubs, the stack can be accessed via
L<Test2::API::test2_stack>. When you get a context it will find the current
hub, if there is no current hub then the root one will be initialized.
=head2 PROVIDE HOOKS
There are hooks that run when contexts are created, found, and released. See
L<Test2::API> for details on these hooks and how to use them.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,376 @@
package Test2::Manual::Anatomy::EndToEnd;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::EndToEnd - Overview of Test2 from load to finish.
=head1 DESCRIPTION
This is a high level overview of everything from loading Test2 through the end
of a test script.
=head1 WHAT HAPPENS WHEN I LOAD THE API?
use Test2::API qw/context/;
=over 4
=item A singleton instance of Test2::API::Instance is created.
You have no access to this, it is an implementation detail.
=item Several API functions are defined that use the singleton instance.
You can import these functions, or use them directly.
=item Then what?
It waits...
The API intentionally does as little as possible. At this point something can
still change the formatter, load L<Test2::IPC>, or have other global effects
that need to be done before the first L<Test2::API::Context> is created. Once
the first L<Test2::API::Context> is created the API will finish initialization.
See L</"WHAT HAPPENS WHEN I ACQUIRE A CONTEXT?"> for more information.
=back
=head1 WHAT HAPPENS WHEN I USE A TOOL?
This section covers the basic workflow all tools such as C<ok()> must follow.
sub ok($$) {
my ($bool, $name) = @_;
my $ctx = context();
my $event = $ctx->send_event('Ok', pass => $bool, name => $name);
...
$ctx->release;
return $bool;
}
ok(1, "1 is true");
=over 4
=item A tool function is run.
ok(1, "1 is true");
=item The tool acquires a context object.
my $ctx = context();
See L</"WHAT HAPPENS WHEN I ACQUIRE A CONTEXT?"> for more information.
=item The tool uses the context object to create, send, and return events.
See L</"WHAT HAPPENS WHEN I SEND AN EVENT?"> for more information.
my $event = $ctx->send_event('Ok', pass => $bool, name => $name);
=item When done the tool MUST release the context.
See L</"WHAT HAPPENS WHEN I RELEASE A CONTEXT?"> for more information.
$ctx->release();
=item The tool returns.
return $bool;
=back
=head1 WHAT HAPPENS WHEN I ACQUIRE A CONTEXT?
my $ctx = context();
These actions may not happen exactly in this order, but that is an
implementation detail. For the purposes of this document this order is used to
help the reader understand the flow.
=over 4
=item $!, $@, $? and $^E are captured and preserved.
Test2 makes a point to preserve the values of $!, $@, $? and $^E such that the test
tools do not modify these variables unexpectedly. They are captured first thing
so that they can be restored later.
=item The API state is changed to 'loaded'.
The 'loaded' state means that test tools have already started running. This is
important as some plugins need to take effect before any tests are run. This
state change only happens the first time a context is acquired, and may trigger
some hooks defined by plugins to run.
=item The current hub is found.
A context attaches itself to the current L<Test2::Hub>. If there is no current
hub then the root hub will be initialized. This will also initialize the hub
stack if necessary.
=item Context acquire hooks fire.
It is possible to create global, or hub-specific hooks that fire whenever a
context is acquired, these hooks will fire now. These hooks fire even if there
is an existing context.
=item Any existing context is found.
If the current hub already has a context then a clone of it will be used
instead of a completely new context. This is important because it allows nested
tools to inherit the context used by parent tools.
=item Stack depth is measured.
Test2 makes a point to catch mistakes in how the context is used. The stack
depth is used to accomplish this. If there is an existing context the depth
will be checked against the one found here. If the old context has the same
stack depth, or a shallower one, it means a tool is misbehaving and did not
clean up the context when it was done, in which case the old context will be
cleaned up, and a warning issued.
=item A new context is created (if no existing context was found)
If there is no existing context, a new one will be created using the data
collected so far.
=item Context init hooks fire (if no existing context was found)
If a new context was created, context-creation hooks will fire.
=item $!, $@, $?, and $^E are restored.
We make sure $!, $@, $?, and $^E are unchanged at this point so that changes we
made will not effect anything else. This is done in case something inside the
context construction accidentally changed these vars.
=item The context is returned.
You have a shiney new context object, or a clone of the existing context.
=back
=head1 WHAT HAPPENS WHEN I SEND AN EVENT?
my $event = $ctx->send_event('Ok', pass => $bool, name => $name);
=over 4
=item The Test2::Event::Ok module is loaded.
The C<send_event()> method will automatically load any Event package necessary.
Normally C<send_event()> will assume the first argument is an event class
without the C<Test2::Event::> prefix, which it will add for you. If you want to
use an event class that is in a different namespace you can prefix the class
name with a C<+> to tell the tool that you are giving a fully qualified class
name:
my $event = $ctx->send_event('+Fully::Qualified::Event', pass => $bool, name => $name);
=item A new instance of Test2::Event::Ok is created.
The event object is instantiated using the provided parameters.
=item The event object is sent to the hub.
The hub takes over from here.
=item The hub runs the event through any filters.
Filters are able to modify or remove events. Filters are run first, before the
event can modify global test state.
=item The global test state is updated to reflect the event.
If the event effects test count then the count will be incremented. If the
event causes failure then the failure count will be incremented. There are a
couple other ways the global state can be effected as well.
=item The event is sent to the formatter
After the state is changed the hub will send the event to the formatter for
rendering. This is where TAP is normally produced.
=item The event is sent to all listeners.
There can be any number of listeners that take action when events are
processed, this happens now.
=back
=head1 WHAT HAPPENS WHEN I RELEASE A CONTEXT?
$ctx->release;
=over 4
=item The current context clone is released.
If your tool is nested inside another, then releasing will simply destroy the
copy of the context, nothing else will happen.
=item If this was the canonical context, it will actually release
When a context is created it is considered 'canon'. Any context obtained by a
nested tool will be considered a child context linked to the canonical one.
Releasing child contexts does not do anything of note (but is still required).
=item Release hooks are called
Release hooks are the main motivation behind making the C<release()> method,
and making it a required action on the part of test tools. These are hooks that
we can have called when a tool is complete. This is how plugins like
L<Test2::Plugin::DieOnFail> are implemented. If we simply had a destructor call
the hooks then we would be unable to write this plugin as a C<die> inside of a
destructor is useless.
=item The context is cleared
The main context data is cleared allowing the next tool to create a new
context. This is important as the next tool very likely has a new line number.
=item $!, $@, $?, and $^E are restored
When a Test2 tool is complete it will restore $@, $!, $? and $^E to avoid action at
a distance.
=back
=head1 WHAT HAPPENS WHEN I USE done_testing()?
done_testing();
=over 4
=item Any pending IPC events will be culled.
If IPC is turned on, a final culling will take place.
=item Follow-up hooks are run
The follow-up hooks are a way to run actions when a hub is complete. This is
useful for adding cleanup tasks, or final tests to the end of a test.
=item The final plan event is generated and processed.
The final plan event will be produced using the current test count as the
number of tests planned.
=item The current hub is finalized.
This will mark the hub is complete, and will not allow new events to be
processed.
=back
=head1 WHAT HAPPENS WHEN A TEST SCRIPT IS DONE?
Test2 has some behaviors it runs in an C<END { ... }> block after tests are
done running. This end block does some final checks to warn you if something
went wrong. This end block also sets the exit value of the script.
=over 4
=item API Versions are checked.
A warning will be produced if L<Test::Builder> is loaded, but has a different
version compared to L<Test2::API>. This situation can happen if you downgrade
to an older Test-Simple distribution, and is a bad situation.
=item Any remaining context objects are cleaned up.
If there are leftover context objects they will need to be cleaned up. A
leftover context is never a good thing, and usually requires a warning. A
leftover context could also be the result of an exception being thrown which
terminates the script, L<Test2> is fairly good at noticing this and not warning
in these cases as the warning would simply be noise.
=item Child processes are sent a 'waiting' event.
If IPC is active, a waiting event is sent to all child processes.
=item The script will wait for all child processes and/or threads to complete.
This happens only when IPC is loaded, but Test::Builder is not. This behavior
is useful, but would break compatibility for legacy tests.
=item The hub stack is cleaned up.
All hubs are finalized starting from the top. Leftover hubs are usually a bad
thing, so a warning is produced if any are found.
=item The root hub is finalized.
This step is a no-op if C<done_testing()> was used. If needed this will mark
the root hub as finished.
=item Exit callbacks are called.
This is a chance for plugins to modify the final exit value of the script.
=item The scripts exit value ($?) is set.
If the test encountered any failures this will be set to a non-zero value. If
possible this will be set to the number of failures, or 255 if the number is
larger than 255 (the max value allowed).
=item Broken module diagnostics
Test2 is aware of many modules which were broken by Test2's release. At this
point the script will check if any known-broken modules were loaded, and warn
you if they were.
B<Note:> This only happens if there were test failures. No broken module
warnings are produced on a success.
=back
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,416 @@
package Test2::Manual::Anatomy::Event;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy::Event - The internals of events
=head1 DESCRIPTION
Events are how tools effect global state, and pass information along to the
harness, or the human running the tests.
=head1 HISTORY
Before proceeding it is important that you know some history of events.
Initially there was an event API, and an event would implement the API to
produce an effect. This API proved to be lossy and inflexible. Recently the
'facet' system was introduced, and makes up for the shortcoming and
inflexibility of the old API.
All events must still implement the old API, but that can be largely automated
if you use the facet system effectively. Likewise essential facets can often be
deduced from events that only implement the old API, though their information
maybe less complete.
=head1 THE EVENT OBJECT
All event objects must subclass L<Test2::Event>. If you inherit from this base
class, and implement the old API properly, facets will be generated for you for
free. On the other hand you can inherit from this, and also import
L<Test2::Util::Facets2Legacy> which will instead rely on your facet data, and
deduce the old API from them.
All new events C<MUST> implement both APIs one way or the other. A common way
to do this is to simply implement both APIs directly in your event.
Here is a good template for a new event:
package Test2::Event::Mine;
use strict;
use warnings;
use parent 'Test2::Event';
use Test2::Util::Facets2Legacy ':ALL';
sub facet_data {
my $self = shift;
# Adds 'about', 'amnesty', and 'trace' facets
my $out = $self->common_facet_data;
# Add any additional facets to the $out hashref
...
return $out;
}
1;
=head1 THE FACET API
The new API is a single method: C<facet_data()>. This method must return a
hashref where each key is specific to a facet type, and the value is either a
facet hashref, or an array of hashrefs. Some facets C<MUST> be lone hashrefs,
others C<MUST> be hashrefs inside an arrayref.
The I<standard> facet types are as follows:
=over 4
=item assert => {details => $name, pass => $bool, no_debug => $bool, number => $maybe_int}
Documented in L<Test2::EventFacet::Assert>. An event may only have one.
The 'details' key is the name of the assertion.
The 'pass' key denotes a passing or failing assertion.
The 'no_debug' key tells any harness or formatter that diagnostics should not
be added automatically to a failing assertion (used when there are custom
diagnostics instead).
The 'number' key is for harness use, never set it yourself.
=item about => {details => $string, no_display => $bool, package => $pkg}
Documented in L<Test2::EventFacet::About>. An event may only have one.
'details' is a human readable string describing the overall event.
'no_display' means that a formatter/harness should hide the event.
'package' is the package of the event the facet describes (IE: L<Test2::Event::Ok>)
=item amnesty => [{details => $string, tag => $short_string, inherited => $bool}]
Documented in L<Test2::EventFacet::Amnesty>. An event may have multiple.
This event is how things like 'todo' are implemented. Amnesty prevents a
failing assertion from causing a global test failure.
'details' is a human readable description of why the failure is being granted
amnesty (IE The 'todo' reason)
'tag' is a short human readable string, or category for the amnesty. This is
typically 'TODO' or 'SKIP'.
'inherited' is true if the amnesty was applied in a parent context (true if
this test is run in a subtest that is marked todo).
=item control => {details => $string, global => $bool, terminate => $maybe_int, halt => $bool, has_callback => $bool, encoding => $enc}
Documented in L<Test2::EventFacet::Control>. An event may have one.
This facet is used to apply extra behavior when the event is processed.
'details' is a human readable explanation for the behavior.
'global' true if this event should be forwarded to, and processed by, all hubs
everywhere. (bail-out uses this)
'terminate' this should either be undef, or an integer. When defined this will
cause the test to exit with the specific exit code.
'halt' is used to signal any harness that no further test files should be run
(bail-out uses this).
'has_callback' is set to true if the event has a callback sub defined.
'encoding' used to tell the formatter what encoding to use.
=item errors => [{details => $string, tag => $short_string, fail => $bool}]
Documented in L<Test2::EventFacet::Error>. An event may have multiple.
'details' is a human readable explanation of the error.
'tag' is a short human readable category for the error.
'fail' is true if the error should cause test failure. If this is false the
error is simply informative, but not fatal.
=item info => [{details => $string, tag => $short_string, debug => $bool, important => $bool}]
Documented in L<Test2::EventFacet::Info>. An event may have multiple.
This is how diag and note are implemented.
'details' human readable message.
'tag' short category for the message, such as 'diag' or 'note'.
'debug' is true if the message is diagnostics in nature, this is the main
difference between a note and a diag.
'important' is true if the message is not diagnostics, but is important to have
it shown anyway. This is primarily used to communicate with a harness.
=item parent => {details => $string, hid => $hid, children => [...], buffered => 1}
Documented in L<Test2::EventFacet::Parent>. An event may have one.
This is used by subtests.
'details' human readable name of the subtest.
'hid' subtest hub id.
'children' an arrayref containing facet_data instances from all child events.
'buffered' true if it was a buffered subtest.
=item plan => {details => $string, count => $int, skip => $bool, none => $bool}
Documented in L<Test2::EventFacet::Plan>. An event may have one.
'details' is a human readable string describing the plan (for instance, why a
test is skipped)
'count' is the number of expected assertions (0 for skip)
'skip' is true if the plan is to skip the test.
'none' used for Test::More's 'no_plan' plan.
=item trace => {details => $string, frame => [$pkg, $file, $line, $sub], pid => $int, tid => $int, cid => $cid, hid => $hid, nested => $int, buffered => $bool}
Documented in L<Test2::EventFacet::Trace>. An event may have one.
This is how debugging information is tracked. This is taken from the context
object at event creation.
'details' human readable debug message (otherwise generated from frame)
'frame' first 4 fields returned by caller:
C<[$package, $file, $line, $subname]>.
'pid' the process id in which the event was created.
'tid' the thread is in which the event was created.
'cid' the id of the context used to create the event.
'hid' the id of the hub to which the event was sent.
'nest' subtest nesting depth of the event.
'buffered' is true if the event was generated inside a buffered subtest.
=back
Note that ALL facet types have a 'details' key that may have a string. This
string should always be human readable, and should be an explanation for the
facet. For an assertion this is the test name. For a plan this is the reason
for the plan (such as skip reason). For info it is the human readable
diagnostics message.
=head2 CUSTOM FACETS
You can write custom facet types as well, simply add a new key to the hash and
populated it. The general rule is that any code looking at the facets should
ignore any it does not understand.
Optionally you can also create a package to document your custom facet. The
package should be proper object, and may have additional methods to help work
with your facet.
package Test2::EventFacet::MyFacet;
use parent 'Test2::EventFacet';
sub facet_key { 'myfacet' }
sub is_list { 0 }
1;
Your facet package should always be under the Test2::EventFacet:: namespace if
you want any tools to automatically find it. The last part of the namespace
should be the non-plural name of your facet with only the first word
capitalized.
=over 4
=item $string = $facet_class->facet_key
The key for your facet should be the same as the last section of
the namespace, but all lowercase. You I<may> append 's' to the key if your
facet is a list type.
=item $bool = $facet_class->is_list
True if an event should put these facets in a list:
{ myfacet => [{}, {}] }
False if an event may only have one of this type of facet at a time:
{ myfacet => {} }
=back
=head3 EXAMPLES
The assert facet is not a list type, so its implementation would look like this:
package Test2::EventFacet::Assert;
sub facet_key { 'assert' }
sub is_list { 0 }
The amnesty facet is a list type, but amnesty does not need 's' appended to
make it plural:
package Test2::EventFacet::Amnesty;
sub facet_key { 'amnesty' }
sub is_list { 1 }
The error facet is a list type, and appending 's' makes error plural as errors.
This means the package name is '::Error', but the key is 'errors'.
package Test2::EventFacet::Error;
sub facet_key { 'errors' }
sub is_list { 1 }
B<Note> Do not worry too much about getting the key/pluralization wrong. Most
tools will use L<Module::Pluggable> to load all facet types and build a hash
linking keys to packages and so on, working backwards. This means, in general,
that even if you get it wrong any tool that NEEDS the package for the facet
will find it.
B<Note2:> In practice most tools completely ignore the facet packages, and work
with the facet data directly in its raw structure. This is by design and
recommended. The facet data is intended to be serialized frequently and passed
around. When facets are concerned, data is important, classes and methods are
not.
=head1 THE OLD API
The old API was simply a set of methods you were required to implement:
=over 4
=item $bool = $e->causes_fail
Returns true if this event should result in a test failure. In general this
should be false.
=item $bool = $e->increments_count
Should be true if this event should result in a test count increment.
=item $e->callback($hub)
If your event needs to have extra effects on the L<Test2::Hub> you can override
this method.
This is called B<BEFORE> your event is passed to the formatter.
=item $num = $e->nested
If this event is nested inside of other events, this should be the depth of
nesting. (This is mainly for subtests)
=item $bool = $e->global
Set this to true if your event is global, that is ALL threads and processes
should see it no matter when or where it is generated. This is not a common
thing to want, it is used by bail-out and skip_all to end testing.
=item $code = $e->terminate
This is called B<AFTER> your event has been passed to the formatter. This
should normally return undef, only change this if your event should cause the
test to exit immediately.
If you want this event to cause the test to exit you should return the exit
code here. Exit code of 0 means exit success, any other integer means exit with
failure.
This is used by L<Test2::Event::Plan> to exit 0 when the plan is
'skip_all'. This is also used by L<Test2::Event:Bail> to force the test
to exit with a failure.
This is called after the event has been sent to the formatter in order to
ensure the event is seen and understood.
=item $msg = $e->summary
This is intended to be a human readable summary of the event. This should
ideally only be one line long, but you can use multiple lines if necessary. This
is intended for human consumption. You do not need to make it easy for machines
to understand.
The default is to simply return the event package name.
=item ($count, $directive, $reason) = $e->sets_plan()
Check if this event sets the testing plan. It will return an empty list if it
does not. If it does set the plan it will return a list of 1 to 3 items in
order: Expected Test Count, Test Directive, Reason for directive.
=item $bool = $e->diagnostics
True if the event contains diagnostics info. This is useful because a
non-verbose harness may choose to hide events that are not in this category.
Some formatters may choose to send these to STDERR instead of STDOUT to ensure
they are seen.
=item $bool = $e->no_display
False by default. This will return true on events that should not be displayed
by formatters.
=back
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,120 @@
package Test2::Manual::Anatomy::Hubs;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy::Hubs - Internals documentation for the hub stack, and
hubs.
=head1 DESCRIPTION
This document describes the hub stack, and the hubs it contains. It explains
why we have a stack, and when to add/remove hubs from it.
=head1 WHAT IS A HUB?
Test2 is an event system, tools generate events, those events are then
processed to modify the testing state (number of tests, number of failures,
etc). The hub is responsible for receiving and processing events to record the
change in state. All events should eventually reach a destination hub.
The base hub is L<Test2::Hub>. All hub classes should inherit from the base hub
class. The base hub class provides several hooks that allow you to monitor or
modify events. Hubs are also responsible for forwarding events to the output
formatter.
=head1 WHY DO WE HAVE A HUB STACK?
There are cases where it makes sense to have more than one hub:
=over 4
=item subtests
In Test2 subtests are implemented using the hub stack. When you start a subtest
a new L<Test2::Hub::Subtest> instance is created and pushed to the stack. Once
this is done all calls to C<Test2::API::context> will find the new hub and send
all events to it. When the subtest tool is complete it will remove the new hub,
and send a final subtest event to the parent hub.
=item testing your test tools
C<Test2::API::intercept()> is implemented using the hub stack. The
C<Test2::API::intercept()> function will add an L<Test2::Hub::Interceptor>
instance to the stack, any calls to L<Test2::API::context()> will find the new
hub, and send it all events. The intercept hub is special in that is has no
connection to the parent hub, and usually does not have a formatter.
=back
=head1 WHEN SHOULD I ADD A HUB TO THE STACK?
Any time you want to intercept or block events from effecting the test state.
Adding a new hub is essentially a way to create a sandbox where you have
absolute control over what events do. Adding a new hub insures that the main
test state will not be effected.
=head1 WHERE IS THE STACK?
The stack is an instance of L<Test2::API::Stack>. You can access the global hub
stack using C<Test2::API::test2_stack>.
=head1 WHAT ABOUT THE ROOT HUB?
The root hub is created automatically as needed. A call to
C<< Test2::API::test2_stack->top() >> will create the root hub if it does not
already exist.
=head1 HOW DO HUBS HANDLE IPC?
If the IPC system (L<Test2::IPC>) was not loaded, then IPC is not handled at
all. Forking or creating new threads without the IPC system can cause
unexpected problems.
All hubs track the PID and Thread ID that was current when they were created.
If an event is sent to a hub in a new process/thread the hub will detect this
and try to forward the event along to the correct process/thread. This is
accomplished using the IPC system.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,90 @@
package Test2::Manual::Anatomy::IPC;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy::IPC - Manual for the IPC system.
=head1 DESCRIPTION
This document describes the IPC system.
=head1 WHAT IS THE IPC SYSTEM
The IPC system is activated by loading L<Test2::IPC>. This makes hubs
process/thread aware, and makes them forward events along to the parent
process/thread as necessary.
=head1 HOW DOES THE IPC SYSTEM EFFECT EVERYTHING?
L<Test2::API> and L<Test2::API::Instance> have some behaviors that trigger if
L<Test2::IPC> is loaded before the global state is initialized. Mainly an IPC
driver will be initiated and stored in the global state.
If an IPC driver is initialized then all hubs will be initialized with a
reference to the driver instance. If a hub has an IPC driver instance it will
use it to forward events to parent processes and threads.
=head1 WHAT DOES AN IPC DRIVER DO?
An L<Test2::IPC::Driver> provides a way to send event data to a destination
process+thread+hub (or to all globally). The driver must also provide a way for
a process/thread/hub to read in any pending events that have been sent to it.
=head1 HOW DOES THE DEFAULT IPC DRIVER WORK?
The default IPC driver is L<Test2::API::Driver::Files>. This default driver,
when initialized, starts by creating a temporary directory. Any time an event
needs to be sent to another process/thread/hub, the event will be written to a
file using L<Storable>. The file is written with the destination process,
thread, and hub as part of the filename. All hubs will regularly check for
pending IPC events and will process them.
This driver is further optimized using a small chunk of SHM. Any time a new
event is sent via IPC the shm is updated to have a new value. Hubs will not
bother checking for new IPC events unless the shm value has changed since their
last poll. A result of this is that the IPC system is surprisingly fast, and
does not waste time polling the hard drive when there are no pending events.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,76 @@
package Test2::Manual::Anatomy::Utilities;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy::Utilities - Overview of utilities for Test2.
=head1 DESCRIPTION
This is a brief overview of the utilities provided by Test2.
=head1 Test2::Util
L<Test2::Util> provides functions to help you find out about the current
system, or to run generic tasks that tend to be Test2 specific.
This utility provides things like an internal C<try {...}> implementation, and
constants for things like threading and forking support.
=head1 Test2::Util::ExternalMeta
L<Test2::Util::ExternalMeta> allows you to quickly and easily attach meta-data
to an object class.
=head1 Test2::Util::Facets2Legacy
L<Test2::Util::Facets2Legacy> is a set of functions you can import into a more
recent event class to provide the classic event API.
=head1 Test2::Util::HashBase
L<Test2::Util::HashBase> is a local copy of L<Object::HashBase>. All object
classes provided by L<Test2> use this to generate methods and accessors.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut