Skipping code with Byteman?
ron_sigal Sep 26, 2013 1:49 AMI want to post to the forum a conversation I had with Andrew, in the hope it might be useful to someone.
------------------------------------------------------------------------------------------------------------------------------------
Hi Ron,
On 22/09/13 01:59, Ron Sigal wrote:
> I have a question about byteman. I'm starting to work on
> internationalizing Resteasy (the deal I made with Bill was that I would
> do the boring stuff he didn't want to do ), and I'm debating whether
> to go to the trouble of testing each log statement in place. If I do
> that, I'm thinking that Byteman would be useful. Now, I've just started
> looking at the first place I would want to use Byteman, and I don't see
> how to do what I want to do.
Hmm, this will probably require a little bit of Byteman trickery to make
it work.
> The code is
>
try
{
Context context = new InitialContext();
validatorFactory = tmpValidatorFactory = ValidatorFactory.class.cast(context.lookup("java:comp/ValidatorFactory"));
LogMessages.LOGGER.supportingCDI(validatorFactory);
}
catch (NamingException e)
{
LogMessages.LOGGER.unableToSupportCDI();
HibernateValidatorConfiguration config = Validation.byProvider(HibernateValidator.class).configure();
validatorFactory = tmpValidatorFactory = config.buildValidatorFactory();
}
>
> Running out of the box and outside of AS, the call to context.lookup()
> will throw the NamingException, and I'd like to skip over that call to
> get to LogMessages.LOGGER.supportingCDI(validatorFactory). That's what
> I don't see how to do. Is there a way to skip code?
Well no, Byteman doesn't give you that directly. For the most part it
works by injecting *extra* code into the existing code. However, you can
change control flow or spoof return values using a THROW or RETURN
action and in this case the latter option ought to allow you to engineer
the situation you want.
You need to short circuit the context lookup so it returns a dummy value
before it tries to check its argument. IT can return any object but
since the caller is expecting it to return a class let's just use the
InitialContext object's class.
RULE context lookup force early return
CLASS InitialContext
METHOD lookup
AT ENTRY
IF callerEquals("xxx", "yyy", true)
DO RETURN $0.getClass();
ENDRULE
$0 refers to the InitialContext instance which is executing the lookup
method. The IF condition uses Byteman built-in 'callerEquals' to
identify the caller of InitialContext.lookup (with this argument pattern
by method name and non-package qualified class name but other formats
allow you to be more or less specific). The builtin call needs to have
the name and class of the calling method inserted in place of "xxx" and
"yyy" (i.e. the one you have excerpted this snippet of code from).
The rule condition makes sure that the call is only bypassed when the
lookup method is called from this point in the codebase. It's probably
overkill for your test since this is likely the only call to
InitialContext.lookup but in general you need some sort of guard liek
this when trying to short circuit code during testing.
The returned value (InitialContext.class) will now be passed to the cast
call and it will return null which will then be passed to the Logger call.
> I just think it would be awesome to not have to change the code to
> support testing.
Yes, that's the primary goal of Byteman -- to test as much 'real' code
as possible. Nothing worse than finding out that your tests pass but the
real code still fails because it's not the same as the test.