Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to run another test as a sub-process? #934

Open
jimav opened this issue May 14, 2023 · 6 comments
Open

How to run another test as a sub-process? #934

jimav opened this issue May 14, 2023 · 6 comments

Comments

@jimav
Copy link

jimav commented May 14, 2023

This may not be a bug, but I'm confounded trying to understand how to do a seemingly-simple thing in a test: Execute a separate, independent test script in a sub-process.

What I actually want is to repeat a large test several times, varying a parameter (passed on the command line). The test to be repeated mucks with globals and can not be simply wrapped in a loop because of undesired carry-over state; so the test must be re-run in a new process each time.

Without using sub-processes, this seems to work:

# t/99_demo.t (no sub-processes)
use Test2::V0;
use Test2::Tools::Subtest qw/subtest_buffered/;

subtest_buffered st1 => sub{ ok(1, "DD"); done_testing; };
subtest_buffered st2 => sub{ for (1..($ARGV[0]//42)) { ok(1) } done_testing; };
done_testing();

prove t/99_demo.t succeeds.

However a similar test using sub-processes does not. It seems like
the "separate" sub-process somehow hooks itself into the parent process's test harness, and that doesn't play nicely.

# t/100_demo.t
use Test2::V0;
use Test2::Tools::Subtest qw/subtest_buffered/;

subtest_buffered st1 => sub {
  my $wstat = system $^X, '-wE', 'use Test2::V0; for (1..$ARGV[0]//1) { ok(1) } done_testing();', 42;
  ok($wstat==0, "st1 succeeded");
  done_testing();
};
done_testing();

prove 1/100_demo.t says

t/100_demo.t .. All 42 subtests passed 

Test Summary Report
-------------------
t/100_demo.t (Wstat: 0 Tests: 43 Failed: 1)
  Failed test:  1
  Parse errors: Plan (1..42) must be at the beginning or end of the TAP output
                Tests out of sequence.  Found (1) but expected (43)
                More than one plan found in TAP output
                Bad plan.  You planned 42 tests but ran 43.

By the way, I tried just running the sub-processes without using subtest_buffered and got similar TAPish wierdness.

I read about Test2::API::intercept but couldn't figure out how to re-inject the captured events into the main test so success/failure was properly recorded. I figured I should not try to decode the event structures myself.

Any guidance would be greatly appreciated!

@jimav jimav changed the title Subtests can not use 'done_testing()', or how to run another test as a sub-process? How to run another test as a sub-process? May 14, 2023
@rabbiveesh
Copy link

rabbiveesh commented May 14, 2023 via email

@jimav
Copy link
Author

jimav commented May 14, 2023

Have you taken a look at Test2::Tools::Spec?
You can have the test fix up state in before blocks.

Hi rabbiveesh,
What is meant by "fix up state"? What exactly is wrong with the test state and what needs to be fixed? I'm happy to read docs if you point me.

Merely running the subordinate test script in an 'iso' block (supposedly completely isolated) still causes errors:

# t/103_demo.t
use Test2::V0;
use Test2::Tools::Spec;

describe foo => sub {
  tests exttest => { iso => 1 }, sub {
    my $wstat = system $^X, '-wE', 'use Test2::V0; ok(1); done_testing();';
    ok($wstat==0, "st1 succeeded");
  };
};
done_testing();

prove t/103_demo.t says:

t/103_demo.t .. All 1 subtests passed 

Test Summary Report
-------------------
t/103_demo.t (Wstat: 0 Tests: 2 Failed: 1)
  Failed test:  1
  Parse errors: Plan (1..1) must be at the beginning or end of the TAP output
                Tests out of sequence.  Found (1) but expected (2)
                More than one plan found in TAP output
                Bad plan.  You planned 1 tests but ran 2.

It seems like events from the "isolated" subtest are corrupting the outer test's state.

@exodist
Copy link
Member

exodist commented May 14, 2023

The problem here is that you loose internal state when you launch your sub-process.

When you call system($^X, ...) it forks a new process, then replaces the process with exec. At this time the new process has no context from the first process. It does not know that tests have started, it does not know that it is in a subtest. It is just a completely new perl process loading a new instance of the test2 framework and making assertions.

To do what you want you need to change your approach. Instead of using system() you need to use fork(). Then in the new process use 'do()' or 'require' to run the test file you want in the subtest.

Also to make all this work you need to load Test2::IPC first thing in the parent process to make the different process talk to each-other.

Currently there is no way to convey the existing state (or fact you are in a subtest) to a child process except by forking and maintaining state, IE not calling exec() or system().

What you want is theoretically possible to implement, possibly with env vars, but it does not exist now, and is not trivial.

@jimav
Copy link
Author

jimav commented Jun 25, 2023 via email

@sanko
Copy link

sanko commented May 6, 2024

I'm trying to run parts of my test suite under valgrind so fork or threads won't work for me either. Before I spend too much time trying to figure out a way to share state though Test2::IPC::Driver::File objects pointing at the same directory or something, did you ever get this up and running, @jimav?

@jimav
Copy link
Author

jimav commented May 7, 2024

@sanko - no, I ended up replacing all the Test2 calls in the 'subtest' with code which just dies if the answer is wrong. Then the parent process calls Test2's "fail()" if the exit status is non-zero. Crude but it let me move on.

@exodist exodist transferred this issue from Test-More/Test2-Suite Aug 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants