"Special" AOP UseCase - java

I have some compiled library which contains a method like this:
public boolean foo(String userID) {
Class<?> ntSystemClass = Thread.currentThread().getContextClassLoader()
.loadClass("com.sun.security.auth.module.NTSystem");
Method getNameMethod = ntSystemClass.getMethod("getName", null);
Object ntSystem = ntSystemClass.newInstance();
String name = (String)getNameMethod.invoke(ntSystem, null);
boolean same=userID.equalsIgnoreCase(name);
if (same) {
// more work done here
} else {
// more work done here
}
}
For some rather special use case I need to ensure that the boolean same is always true.
My first approach was extending the class and overriding the method foo() but that wasn't realizable because within the method many references on other library private stuff is required.
So the next approach is using AOP. I tried a few things with AspectJ but didn't find a solution. Can anyone help we with this? As far as I understand I can't alter the boolean same directly. Is there a possibility to address the String name = (String)getNameMethod.invoke(ntSystem, null); in any way just within the library?

Let us talk straight here: Henceforth I am assuming that your "special use case" is that you want to tweak/hack user authentication, hopefully in a legal way for testing or whatever.
The main problems to be solved are:
It would be easy to just manipulate the result of your foo method (I have renamed it to isCurrentUser(String userID) to clarify its intent). But if I understand correctly, the method has side effects, i.e. it calls other methods, and you want to keep those side effects. So we have to be more careful and use a scalpel, not an axe.
There is no pointcut for local variable changes so you have to intercept the method execution or call which changes the local variable's value.
AspectJ cannot normally intercept JDK method execution() (unless you want to weave the JDK first, which is possible but out of scope here). Thus, you have to intercept the call() from your own code. I am assuming it is possible to weave into that code even if it is contained in a JAR and you do not have the sources. You can either use LTW for the target class or binary weaving for the JAR, creating a new, woven version of it.
Your method call to NTSystem.getName() is not done in a normal way but via Reflection API. Thus, you cannot just use a pointcut like call(NTSystem.getName()) because it will never be triggered. You have to intercept call(public Object Method.invoke(Object, Object...)).
Theoretically it could be that other reflective method calls are made from within isCurrentUser(..), so we have to refine our pointcut in order to only match if really NTSystem.getName() is called, not any other method.
As a convenience function, we want to be able to dynamically switch the hackingMode on and off.
Now here is a complete, compileable code sample (obviously only working on Windows just like your own code snippet):
Java class with method to be manipulated and main method for demonstration purposes:
package de.scrum_master.app;
import java.lang.reflect.Method;
import de.scrum_master.aspect.TweakAuthenticationAspect;
public class UserAuthentication {
private static final String USER_NAME_GOOD = "alexander"; // Add your own user name here
private static final String USER_NAME_BAD = "hacker";
public static boolean isCurrentUser(String userID) throws Exception {
Class<?> ntSystemClass = Thread.currentThread().getContextClassLoader()
.loadClass("com.sun.security.auth.module.NTSystem");
Method getNameMethod = ntSystemClass.getMethod("getName");
Object ntSystem = ntSystemClass.newInstance();
String currentUserID = (String) getNameMethod.invoke(ntSystem);
boolean same = userID.equalsIgnoreCase(currentUserID);
if (same) {
System.out.println("Do something (same == true)");
} else {
System.out.println("Do something (same == false)");
}
return same;
}
public static void main(String[] args) throws Exception {
testAuthentication(false);
testAuthentication(true);
}
private static void testAuthentication(boolean hackingMode) throws Exception {
TweakAuthenticationAspect.hackingMode = hackingMode;
System.out.println("Testing authentication for hackingMode == " + hackingMode);
System.out.println("Authentication result for " + USER_NAME_GOOD + ": "
+ isCurrentUser(USER_NAME_GOOD));
System.out.println("Authentication result for " + USER_NAME_BAD + ": "
+ isCurrentUser(USER_NAME_BAD));
System.out.println();
}
}
As you can see, testAuthentication(boolean hackingMode) is called twice, once with the hacking code disabled and then enabled. In both cases it tests a good/correct user name (please edit!) first and then a bad one ("hacker").
Aspect manipulating the authentication method:
package de.scrum_master.aspect;
import com.sun.security.auth.module.NTSystem;
import de.scrum_master.app.UserAuthentication;
import java.lang.reflect.Method;
public aspect TweakAuthenticationAspect {
public static boolean hackingMode = false;
pointcut reflectiveCall_NTSystem_getName(NTSystem ntSystem, Method method) :
call(public Object Method.invoke(Object, Object...)) &&
args(ntSystem, *) &&
target(method) &&
if(method.getName().equals("getName"));
pointcut cflow_isCurrentUser(String userID) :
cflow(
execution(* UserAuthentication.isCurrentUser(String)) &&
args(userID)
);
Object around(NTSystem ntSystem, Method method, String userID) :
reflectiveCall_NTSystem_getName(ntSystem, method) &&
cflow_isCurrentUser(userID) &&
if(hackingMode)
{
System.out.println("Join point: " + thisJoinPoint);
System.out.println("Given user ID: " + userID);
System.out.println("Reflectively called method: " + method);
return userID;
}
}
A few words of explanation here:
Pointcut reflectiveCall_NTSystem_getName intercepts calls to Method.invoke(..), restricting the first parameter to NTSystem type, which eliminates reflective calls to other classes. It also checks if the target method is actually getName. I.e. the pointcut checks if really NTSystem.getName()` is to be invoked.
Pointcut cflow_isCurrentUser catches joinpoints in the control flow of method UserAuthentication.isCurrentUser(..), exposing its parameter userID for later use.
The around(NTSystem ntSystem, Method method, String userID) advice combines both pointcuts with && and has access to the three named objects in its signature. In its method body we can do whatever we please with those objects, e.g. print them to the console. We could also change their state, which is not necessary in this case. The advice is activated dynamically via if(hackingMode). If you do not need this, you can remove it, it is just for convenience. Because we use an around() advice here, we can return anything instead of the original method result. In this case, we always return userID, as if the given user was the one currently logged into Windows. This effectively results in the local same variable to become always true because the call to equalsIgnoreCase(..) always returns true as well.
I could also have manipulated the result of equalsIgnoreCase(..) directly, but then local variable currentUserID would be non-equal to userID. Depending on which kinds of side effects you want, you can change this behaviour according to your preferences.
Sample output:
Testing authentication for hackingMode == false
Do something (same == true)
Authentication result for alexander: true
Do something (same == false)
Authentication result for hacker: false
Testing authentication for hackingMode == true
Join point: call(Object java.lang.reflect.Method.invoke(Object, Object[]))
Given user ID: alexander
Reflectively called method: public java.lang.String com.sun.security.auth.module.NTSystem.getName()
Do something (same == true)
Authentication result for alexander: true
Join point: call(Object java.lang.reflect.Method.invoke(Object, Object[]))
Given user ID: hacker
Reflectively called method: public java.lang.String com.sun.security.auth.module.NTSystem.getName()
Do something (same == true)
Authentication result for hacker: true
You can see in the upper part that authentication works as usual if hackingMode == false, but will always positively authenticate any given user name if hackingMode == true.

Related

Find all Java methods using only one specific property of a specific type of parameter

We're in the process of trying to identify everywhere that a specific type of object is used only to get a specific property from it, and pass that property into the method instead.
I'm thinking IntelliJ IDEA's "Structural Search" might be a good tool for this, but I'm not sure how to formulate the search template.
A concrete example:
public class MyClass {
public Long getId() {...}
public void setSomethingElse(int se) {...}
}
public class SomeOtherClasses {
public void shouldBeMatched(MyClass mc) {
doSomething();
mc.getId();
doSomethingElse();
}
public void shouldNotBeMatched(MyClass mc) {
doSomething();
mc.getId();
mc.setSomethingElse(14);
doSomethingElse();
}
public void alsoShouldNotBeMatched(MyClass mc) {
shouldBeMatched(mc);
}
}
In the above example, if I'm looking for methods that only use getId, then I should find shouldBeMatched, but not be bothered with shoudNotBeMatched and alsoShouldNotBeMatched, because they do something with the mc object other than call getId().
I'm thinking IntelliJ IDEA's "Structural Search" might be a good tool for this
And it is indeed. The documentation can be tough though.
Let's check Search templates, filters, and script constraints page. It goes as follows.
Let's say, you have a variable that matches a method, a toString()
method. Then this variable is actually a PsiMethod node. Retrieving
variable.parent will produce a PsiClass node, and so forth.
variable.text then will give you the entire text of the method. If you
just need the name of the method, you can use variable.name.
It seems that the task can be done by choosing the right template and writing a corresponding Groovy script.
The template is called methods of the class and can be found under Existing templates. They provide __context__variable to be used with a script.
We have to be sure matched methods have parameters. It is simple enough, just put a count filter on a $Parameter$ variable.
Then we need to extract the name of a parameter of desired type and see if it is called in the body of the method. The following script will do.
def parameters = __context__.getParameterList().getParameters();
def parameter = parameters.find { p -> p.getType().getName().equals('MyClass') };
if (parameter == null) return false;
String parameterName = parameter.getName();
String methodText = __context__.getText();
String occurrence = "${parameterName}.";
String methodCall = "${parameterName}.getId()";
return methodText.count(occurrence) > 0 && methodText.count(occurrence) == methodText.count(methodCall);
Put it in the $Method$ variable filter and verify the results.

What approach to choose when refactoring method, so that it responds to the principles of clean code?

I have this method signature:
public User getActiveUser(String personId, User mainUser) throws MyExceptions {
if (personId== null) return mainUser;
User innerUser = userRepository.getByPersonId(personId);
checkForNull(innerUser);
checkIsActive(innerUser);
return innerUser;
}
private void checkForNull(User innerUser) throws UNPExceptions {
if (innerUser == null) throw new MyExceptions(USER_NOT_FOUND);
}
private void checkIsActive(User innerUser) throws UNPExceptions {
if (!innerUser.getIsActive()) throw new MyExceptions(USER_BLOCKED);
}
And I call this method from different places like this:
User user = userService.getActive(userRequest.getPersonId(), requestEntity.getUser());
I do not like this code because:
1) I pass 2 parameters to this method getActiveUser(String personId, User mainUser)
mainUser always return if personId is null. I can move this check inside method but then I have to do it every time before calling the method. And the method is called from many places. so I moved the check to one place. But it looks crooked and I do not know how to get around it. I don’t want to pass the second parameter just to do this check inside the method, but it looks better than copying this check before each method call. I do not know which solution is better. maybe there is another solution.
2) method name - getActiveUser is lying. because inside I do more checks. but I do not know how to call it - getActiveUserAndCheck? this is also not correct as the method is responsible for several duties
3) Is it necessary to divide checks into separate methods? checkForNull(innerUser);
checkIsActive(innerUser);
If the mainUser is always the same user you don't have to pass it as a method parameter, you can store it as an instance field and initialize it when appropriate.
If that's not the case, you can use AOP to handle the case with null personId and the aspect component will be responsible for retrieving the mainUser.
Using Java8+, you can simply replace
checkForNull(innerUser);
checkIsActive(innerUser);
return innerUser;
by means of Optional, as:
return Optional.ofNullable(innerUser)
.filter(User::getIsActive)
.orElseThrow(() -> new MyExceptions(""));
If you want to default to mainUser, you could do something on these lines(just that this is not throwing your custom exception) :
return Optional.ofNullable(personId) // check for person 'null'
.map(p -> userRepository.getByPersonId(personId)) if present evaluate 'innerUser'
.filter(Objects::nonNull) // check if innerUser is null
.filter(User::getIsActive) // check if innerUser is active
.orElse(defaultUser); if any of above fails return defaultUser

How can I verify that one of two methods was called using Mockito?

Suppose I have a class with two methods where I don't care which is called...
public class Foo {
public String getProperty(String key) {
return getProperty(key, null);
}
public String getProperty(String key, String defaultValue) {
//...
}
}
Both the below (from another class, still in my application) should pass my test:
public void thisShouldPass(String key) {
// ...
String theValue = foo.getProperty(key, "blah");
// ...
}
public void thisShouldAlsoPass(String key) {
// ...
String theValue = foo.getProperty(key);
if (theValue == null) {
theValue = "blah";
}
// ...
}
I don't care which was called, I just want one of the two variants to be called.
In Mockito, I can generally do things like this:
Mockito.verify(foo, atLeastOnce()).getProperty(anyString());
Or:
Mockito.verify(foo, atLeastOnce()).getProperty(anyString(), anyString());
Is there a native way to say "verify either one or the other occurred at least once"?
Or do I have to do something as crude as:
try {
Mockito.verify(foo, atLeastOnce()).getProperty(anyString());
} catch (AssertionError e) {
Mockito.verify(foo, atLeastOnce()).getProperty(anyString(), anyString());
}
You could use atLeast(0) in combination with ArgumentCaptor:
ArgumentCaptor<String> propertyKeyCaptor = ArgumentCaptor.forClass(String.class);
Mockito.verify(foo, atLeast(0)).getProperty(propertyKeyCaptor.capture(), anyString());
ArgumentCaptor<String> propertyKeyCaptor2 = ArgumentCaptor.forClass(String.class);
Mockito.verify(foo, atLeast(0)).getProperty(propertyKeyCaptor2.capture());
List<String> propertyKeyValues = propertyKeyCaptor.getAllValues();
List<String> propertyKeyValues2 = propertyKeyCaptor2.getAllValues();
assertTrue(!propertyKeyValues.isEmpty() || !propertyKeyValues2.isEmpty()); //JUnit assert -- modify for whatever testing framework you're using
Generally, if you're calling verify on a "getter" of any sort, you're assuming too much about the implementation. Mockito is generally designed for flexible tests (compared to "brittle" test that need to change even if the code is correct); your test should care more about whether the value is correct as opposed to which methods were used to get that value. A better solution might be to stub both getters to return a predictable value, and then use a normal assertion against the same value to ensure it plumbs through to the correct place.
when(mockFoo.getProperty("bar")).thenReturn("bar value");
when(mockFoo.getProperty("bar", anyString())).thenReturn("bar value");
// ...
assertEquals("bar value", new SystemUnderTest(mockFoo).getBarProperty());
Mockito's documentation spells this out:
Although it is possible to verify a stubbed invocation, usually it's just redundant. Let's say you've stubbed foo.bar(). If your code cares what foo.bar() returns then something else breaks (often before even verify() gets executed). If your code doesn't care what get(0) returns then it should not be stubbed.
That said, if this is a pattern you're required to support (or a method call with both overloads and side-effects) you can get a lot of information via Mockito.mockingDetails and MockingDetails.getInvocations, including invocations as of Mockito 1.10.0. You would need to loop through the Invocation objects to check against multiple methods.
boolean found = false;
Method method1 = Foo.class.getMethod("getProperty", String.class);
Method method2 = Foo.class.getMethod("getProperty", String.class, String.class);
for (Invocation invocation : Mockito.mockingDetails(foo).getInvocations()) {
if (method1.equals(invocation.getMethod())
|| method2.equals(invocation.getMethod()) {
found = true;
break;
}
}
assertTrue("getProperty was not invoked", found);
Note that this second solution is a little dangerous, as it does not benefit from automatic refactoring tools built into IDEs, and may be harder to read than some other solutions. (The above may also be missing calls to isIgnoredForVerification, markVerified, and other niceties.) However, if you foresee needing this frequently across a large codebase, then using Mockito's built-in APIs may afford you much more flexibility than you would have otherwise.
In your particular case, getProperty(String) calls getProperty(String, String) internally.
public String getProperty(String key) {
/*
* getProperty(String, String) is called anyway.
* Why not simply verify the occurrence of that?
*/
return getProperty(key, null);
}
Simply verifying the second method would be equivalent to verifying the occurrence of either one or the other at least once.
Mockito.verify(foo, atLeastOnce()).getProperty(anyString(), anyString());

Test a void method with conditioned loop using mockito

I have following method which asks for user input until valid user credentials are entered.It then generates id for that user and sets registered =TRUE.
1.How can I check the value of local variable "registered" from my unit test?
2.How can I assert in my test that while loop executed until "registered" became TRUE?
private void register() {
boolean registered=false;
while(!registered){
try {
String uname =this.read("User Name : ");
char password[] = this.readPassword();
String serverURL = this.read("Server URL : ");
if(!uname.isEmpty() && password!=null && !serverURL.isEmpty()){
registered=this.getUID(uname,password,serverURL);
}
if(registered==false)
System.out.println("\nPlease verify your details and try again!\n");
} catch (UnsupportedEncodingException e) {}
catch(Exception e){}
}
System.out.println("Successful");
}
I have come across usage of ArgumentCaptor to capture variables that a method to be tested, uses to invoke another methods.
e.g verify(mockObj).intArgumentMethod(argument.capture());
However I am not passing variable "registered" to any other method otherwise i would have captured it.
You cannot
By verification:
The loop invariant is that registered is false. So the loop is not entered if it is true
The loop is exited
at the bodies start (in this case it is true)
if a Throwable is thrown, that is not caught by 'catch(Exception e)' (in this case it might be anything)
Anyway - review your testing strategy:
a function has input parameters and output parameters
the input should be part of the fixture:
this.read("User Name : ")
this.readPassword()
this.read("Server URL : ")
this.getUID(uname,password,serverURL) // this may also be viewed as output
the output should be part of the assertions
System.out.println(...)
The input can be set up by creating anonymous sub classes, e.g.
fixture = new YourClass {
public String read(String prompt) {
return mockedString;
}
...
};
The output can be captured/asserted by a Junit Rule, e.g. StandardErrorStreamLog
Mockito is not needed with this example method.
Don't test the implementation details, test the behavior given certain input. If the registered variable is supposed to be some sort of output then it shouldn't be a local variable.
One design I like is to use method objects, it is possible to pass arguments at object creation, and an object method can have multiple return values.
class Registrator {
Registrator(...) { /* assigning needed field */ }
void register() { /* logic that will mutate internal fields */ }
boolean registered() { return registered; }
long triesCount() { return triesCount; }
// ...
}
And one can adapt the code to use a Report object, on which the register method can append success / failure / more details like reasons / etc.
And the test would be much more easy to write.

Verifying partially ordered method invocations in JMockit

I'm trying to write a unit test (using JMockit) that verifies that methods are called according to a partial order. The specific use case is ensuring that certain operations are called inside a transaction, but more generally I want to verify something like this:
Method beginTransaction is called.
Methods operation1 through to operationN are called in any order.
Method endTransaction is called.
Method someOtherOperation is called some time before, during or after the transaction.
The Expectations and Verifications APIs don't seem to be able to handle this requirement.
If I have a #Mocked BusinessObject bo I can verify that the right methods are called (in any order) with this:
new Verifications() {{
bo.beginTransaction();
bo.endTransaction();
bo.operation1();
bo.operation2();
bo.someOtherOperation();
}};
optionally making it a FullVerifications to check that there are no other side-effects.
To check the ordering constraints I can do something like this:
new VerificationsInOrder() {{
bo.beginTransaction();
unverifiedInvocations();
bo.endTransaction();
}};
but this does not handle the someOtherOperation case. I can't replace the unverifiedInvocations with bo.operation1(); bo.operation2() because that puts a total ordering on the invocations. A correct implementation of the business method could call bo.operation2(); bo.operation1().
If I make it:
new VerificationsInOrder() {{
unverifiedInvocations();
bo.beginTransaction();
unverifiedInvocations();
bo.endTransaction();
unverifiedInvocations();
}};
then I get a "No unverified invocations left" failure when someOtherOperation is called before the transaction. Trying bo.someOtherOperation(); minTimes = 0 also doesn't work.
So: Is there a clean way to specify partial ordering requirements on method calls using the Expectations/Verifications API in JMockIt? Or do I have to use a MockClass and manually keep track of invocations, a la:
#MockClass(realClass = BusinessObject.class)
public class MockBO {
private boolean op1Called = false;
private boolean op2Called = false;
private boolean beginCalled = false;
#Mock(invocations = 1)
public void operation1() {
op1Called = true;
}
#Mock(invocations = 1)
public void operation2() {
op2Called = true;
}
#Mock(invocations = 1)
public void someOtherOperation() {}
#Mock(invocations = 1)
public void beginTransaction() {
assertFalse(op1Called);
assertFalse(op2Called);
beginCalled = true;
}
#Mock(invocations = 1)
public void endTransaction() {
assertTrue(beginCalled);
assertTrue(op1Called);
assertTrue(op2Called);
}
}
if you really need such test then: don't use mocking library but create your own mock with state inside that can simply check the correct order of methods.
but testing order of invocations is usually a bad sign. my advice would be: don't test it, refactor. you should test your logic and results rather than a sequence of invocations. check if side effects are correct (database content, services interaction etc). if you test the sequence then your test is basically exact copy of your production code. so what's the added value of such test? and such test is also very fragile (as any duplication).
maybe you should make your code looks like that:
beginTransaction()
doTransactionalStuff()
endTransaction()
doNonTransactionalStuff()
From my usage of jmockit, I believe the answer is no even in the latest version 1.49.
You can implement this type of advanced verification using a MockUp extension with some internal fields to keep track of which functions get called, when, and in what order.
For example, I implemented a simple MockUp to track method call counts. The purpose of this example is real, for where the Verifications and Expectations times fields did not work when mocking a ThreadGroup (useful for other sensitive types as well):
public class CalledCheckMockUp<T> extends MockUp<T>
{
private Map<String, Boolean> calledMap = Maps.newHashMap();
private Map<String, AtomicInteger> calledCountMap = Maps.newHashMap();
public void markAsCalled(String methodCalled)
{
if (methodCalled == null)
{
Log.logWarning("Caller attempted to mark a method string" +
" that is null as called, this is surely" +
" either a logic error or an unhandled edge" +
" case.");
}
else
{
calledMap.put(methodCalled, Boolean.TRUE);
calledCountMap.putIfAbsent(methodCalled, new AtomicInteger()).
incrementAndGet();
}
}
public int methodCallCount(String method)
{
return calledCountMap.putIfAbsent(method, new AtomicInteger()).get();
}
public boolean wasMethodCalled(String method)
{
if (method == null)
{
Log.logWarning("Caller attempted to mark a method string" +
" that is null as called, this is surely" +
" either a logic error or an unhandled edge" +
" case.");
return false;
}
return calledMap.containsKey(method) ? calledMap.get(method) :
Boolean.FALSE;
}
}
With usage like the following, where cut1 is a dynamic proxy type that wraps an actual ThreadGroup:
String methodId = "activeCount";
CalledCheckMockUp<ThreadGroup> calledChecker = new CalledCheckMockUp<ThreadGroup>()
{
#Mock
public int activeCount()
{
markAsCalled(methodId);
return active;
}
};
. . .
int callCount = 0;
int activeCount = cut1.activeCount();
callCount += 1;
Assertions.assertTrue(calledChecker.wasMethodCalled(methodId));
Assertions.assertEquals(callCount, calledChecker.methodCallCount(methodId));
I know question is old and this example doesn't fit OP's use case exactly, but hoping it may help guide others to a potential solution that come looking (or the OP, god-forbid this is still unsolved for an important use case, which is unlikely).
Given the complexity of what OP is trying to do, it may help to override the $advice method in your custom MockUp to ease differentiating and recording method calls. Docs here: Applying AOP-style advice.

Categories