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

Test::DZil/Dist::Zilla::Tester: log is lost if dzil dies in construction. #485

Open
van-de-bugger opened this issue Aug 8, 2015 · 7 comments

Comments

@van-de-bugger
Copy link
Contributor

I want to write some negative tests for my plugin to check error reporting. Unfortunately, Test::DZil/Dist::Zilla::Tester lack support for negative tests. For example, straightforward approach:

my $tzil = Builder->from_config( … );
my $exception = exception { $tzil->build(); };
like( $exception, qr{...}, 'check exception' );
cmd_deeply( $tzil->log_messages, $expected_messages );

does not work if Dist::Zilla or its plugin dies in construction (in from_config class method). Attempts to catch an exception thrown from from_config works:

my $exception = exception{ $tzil = Builder->from_config( … ); };
like( $exception, qr{…} );

but this is not enough for testing: I would like to check the log messages printed by dzil and plugins, but it is not possible, because $tzil assignment is not completed, so $tzil is undefined, $tzil->log_messages does not work, all the messages are lost.

It wold be nice if log messages are saved for later checking.

@van-de-bugger
Copy link
Contributor Author

I have managed the problem by such a trick:

If Dist::Zilla dies in construction, my code saves the exception and creates fake, "stub" builder. Stub builder remembers the exception and original logger. When build method in run on the stub, it just rethrows the exception. In other words, exception raised in construction is saved to be rethrown later.

Such approach allows this code works:

my $tzil = Builder->from_config( … );
    # ^ Exception is saved, not thrown,
    # so we have $tzil initialized anyway,
    # probably with a stub, not real builder.
my $exception = exception { $tzil->build(); };
    # ^ Exception, if any, rethrown.
like( $exception, qr{...}, 'check exception' ); 
cmd_deeply( $tzil->log_messages, $expected_messages );
    # ^ Win: All the log messages available for checking.

This approach is implemented as DistZillaTester.pm module. It is not published separately (yet?), but is a part of my Dist::Zilla plugin.

If you find this acceptable, it could be incorporated to Test::DZil/Dist::Zilla::Tester.

However, I do not think is is the only possible solution. The primary goal: not loosing log messages, may be achieved in other ways. For example, probably the simplest solution would be saving reference to logger object in a global variable:

my $exception = exception { Builder->from_config( … ); };
like( $exception, qr{...}, 'check exception' ); 
cmd_deeply( Builder->log_messages, $expected_messages );

But anyway, log messages should not be lost if builder dies in construction.

@van-de-bugger
Copy link
Contributor Author

Sorry, I have closed in mistakenly.

@van-de-bugger van-de-bugger reopened this Aug 8, 2015
@karenetheridge
Copy link
Contributor

Why not capture the exceptions thrown from $tzil = Builder->from_config(...); ? That's what I do and it works very well.

@van-de-bugger
Copy link
Contributor Author

I would like to check the log messages printed by dzil and plugins, but it is not possible, because $tzil assignment is not completed, so $tzil is undefined, $tzil->log_messages does not work, all the messages are lost.

@karenetheridge
Copy link
Contributor

I mean, what specifically do you need to access in log_messages? Generally the only relevant data is why from_config failed, and that's right there in the exception. Usually it's because something was wrong or missing in the configuration itself, which means Config::MVP died even before returning control back to Dist::Zilla::new (so no logger was ever constructed).

@van-de-bugger
Copy link
Contributor Author

A generic example: A plugin may validate its arguments in BUILD, if something wrong, print some messages with $self->log() and terminate dzil with $self->log_fatal().

A real example: My plugin MetaResources::Template does all the work in its BUILD method.

@rjbs
Copy link
Owner

rjbs commented Sep 1, 2015

Check out my log-log-events branch.

With it, it will store the log events to Builder->most_recent_log_events and Minter->…, even if the object goes away.

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

3 participants