JMeter Groovy: print to log in class (static) (Apparent variable 'log' was found in a static scope but doesn't refer to a local...) - groovy

I want to write to log inside static class in Groovy in JMeter. I can print to terminal inside and outside of class with println or System.out.println. How to do the trick with log? In code below all works except log.warn inside class, give error:
Script53.groovy: 13: Apparent variable 'log' was found in a static scope but doesn't refer to a local variable, static field or class. Possible causes:
You attempted to reference a variable in the binding or an instance variable from a static context.
You misspelled a classname or statically imported field. Please check the spelling.
You attempted to use a method 'log' but left out brackets in a place not allowed by the grammar.
Code:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
class CalcMain {
static void main(def args) throws Exception {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("groovy");
println ("testing 1");
System.out.println ("testing 2");
log.warn("warn2");
}
}
OUT.println("testing 4");
println("testing 5");
log.warn("warn 1");
CalcMain test1 = new CalcMain();
test1.main();
I tried web search but could not find an answer.

You can use Groovy #Log4j annotation:
import groovy.util.logging.Log4j
#Log4j
class CalcMain {
static void main(def args) throws Exception {
// some code
log.info "hello there"
}
}

Another option is to send log as parameter to static method:
static void main(org.slf4j.Logger log) throws Exception {
Call method:
test1.main(log);

I've read https://www.blazemeter.com/blog/top-8-jmeter-java-classes-you-should-be-using-with-groovy/ where it is advised to use log variable but also gives link to Logger class. I've tried to play with Logger class and it works:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class CalcMain {
static void main(def args) throws Exception {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("groovy");
final Logger logger = LoggerFactory.getLogger(CalcMain.class);
logger.warn("My warning");
}
}
CalcMain test1 = new CalcMain();
test1.main();

Related

PowerMockito calls real method on Mocked Object when defining second "when" clause

I am trying to define some different mocked behaviours when a method is called with different parameters. Unfortunately, I find that the second time I try to mock the given method on a (mocked) class, it runs the actual method, causing an exception because the matchers are not valid parameters. Anyone know how I can prevent this?
manager = PowerMockito.mock(Manager.class);
try {
PowerMockito.whenNew(Manager.class).withArguments(anyString(), anyString())
.thenReturn(manager);
} catch (Exception e) {
e.printStackTrace();
}
FindAuthorityDescriptionRequestImpl validFindAuthorityDescription = mock(FindAuthorityDescriptionRequestImpl.class);
PowerMockito.when(manager.createFindAuthorityDescriptionRequest(anyString(), anyString())).thenCallRealMethod();
PowerMockito.when(manager.createFindAuthorityDescriptionRequest(Matchers.eq(VALID_IK),
Matchers.eq(VALID_CATEGORY_NAME))).thenReturn(validFindAuthorityDescription);
PowerMockito.when(manager.processRequest(Matchers.any(FindAuthorityDescriptionRequest.class)))
.thenThrow(ManagerException.class);
PowerMockito.when(manager.processRequest(Matchers.eq(validFindAuthorityDescription)))
.thenReturn(generateValidAuthorityDescriptionResponse());
The following code is a working example based on your mock setup (I've added dummy classes to make it runnable).
The code also contains asserts to verify that the mocked methods return expected values. Also, the real method createFindAuthorityDescriptionRequest is only called once.
Note: This was tested with `powermock 2.0.7` and `mockito 2.21.0`.
If issues persist, I'd suggest checking if the real method is not additionally called from somewhere else in your program (other than the code quoted in your problem statement).
package com.example.stack;
import org.junit.Test;
import org.junit.function.ThrowingRunnable;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.*;
import static org.powermock.api.mockito.PowerMockito.mock;
#RunWith(PowerMockRunner.class)
#PrepareForTest(fullyQualifiedNames = "com.example.stack.*")
public class StackApplicationTests {
private static final String VALID_IK = "IK";
private static final String VALID_CATEGORY_NAME = "CATEGORY_NAME";
private static final Object VALID_RESPONSE = "RESPONSE";
#Test
public void test() {
Manager manager = mock(Manager.class);
try {
PowerMockito.whenNew(Manager.class).withArguments(anyString(), anyString())
.thenReturn(manager);
} catch (Exception e) {
e.printStackTrace();
}
FindAuthorityDescriptionRequestImpl validFindAuthorityDescription = mock(FindAuthorityDescriptionRequestImpl.class);
PowerMockito.when(manager.createFindAuthorityDescriptionRequest(anyString(), anyString())).thenCallRealMethod();
PowerMockito.when(manager.createFindAuthorityDescriptionRequest(eq(VALID_IK), eq(VALID_CATEGORY_NAME)))
.thenReturn(validFindAuthorityDescription);
PowerMockito.when(manager.processRequest(any(FindAuthorityDescriptionRequest.class)))
.thenThrow(ManagerException.class);
PowerMockito.when(manager.processRequest(eq(validFindAuthorityDescription)))
.thenReturn(VALID_RESPONSE);
// verify that the mock returns expected results
assertEquals(Manager.REAL_RESULT, manager.createFindAuthorityDescriptionRequest("any", "any"));
assertEquals(validFindAuthorityDescription, manager.createFindAuthorityDescriptionRequest("IK", "CATEGORY_NAME"));
assertThrows(ManagerException.class, new ThrowingRunnable(){
#Override
public void run( ) {
manager.processRequest(new FindAuthorityDescriptionRequestImpl());
}
});
assertEquals(VALID_RESPONSE, manager.processRequest(validFindAuthorityDescription));
}
}
interface FindAuthorityDescriptionRequest {}
class FindAuthorityDescriptionRequestImpl implements FindAuthorityDescriptionRequest {}
class ManagerException extends RuntimeException {}
class Manager {
public static FindAuthorityDescriptionRequestImpl REAL_RESULT = new FindAuthorityDescriptionRequestImpl();
public Manager(String s1, String s2) {}
public FindAuthorityDescriptionRequest createFindAuthorityDescriptionRequest(String ik, String category) {
return REAL_RESULT;
}
public Object processRequest(FindAuthorityDescriptionRequest request) {
return null;
}
}

Is the #Repeatable annotation not supported by Groovy?

I'm coding in Groovy and am having trouble with the Java 8 #Repeatable meta-annotation. I think I'm doing everything right, but it appears that Groovy is not recognizing #Repeatable. Here's my sample code; I'm expecting the information from both annotations to get stored in MyAnnotationArray:
import java.lang.annotation.*
class MyClass
{
#MyAnnotation(value = "val1")
#MyAnnotation(value = "val2")
void annotatedMethod()
{
println("annotated method called")
}
public static void main(String... args)
{
MyClass ob = new MyClass()
ob.annotatedMethod()
java.lang.reflect.Method m = ob.getClass().getMethod("annotatedMethod")
List annos = m.getAnnotations()
println("annos = $annos")
}
}
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Repeatable(MyAnnotationArray)
public #interface MyAnnotation
{
String value() default "val0";
}
public #interface MyAnnotationArray
{
MyAnnotation[] MyAnnotationArray()
}
What happens is that I get this error:
Caught: java.lang.annotation.AnnotationFormatError: Duplicate annotation for class: interface MyAnnotation: #MyAnnotation(value=val2)
java.lang.annotation.AnnotationFormatError: Duplicate annotation for class: interface MyAnnotation: #MyAnnotation(value=val2)
Which is exactly what I get if I leave out the #Repeatable meta-annotation.
The code works fine if I leave out one of the duplicate MyAnnotations; then there is no error, and I then can read the annotation value as expected.
Is it possible that Groovy doesn't support the #Repeatable meta-annotation? I couldn't find any documentation that states this outright, though this page hints that maybe this is the case (scroll down to item 88).
seems to be not supported
i used java 1.8 and groovy 2.4.11
after compiling and de-compilig the same code i got this:
java:
#MyAnnotationArray({#MyAnnotation("val1"), #MyAnnotation("val2")})
public void annotatedMethod()
{
System.out.println("annotated method called");
}
groovy:
#MyAnnotation("val1")
#MyAnnotation("val2")
public void annotatedMethod()
{
System.out.println("annotated method called");null;
}
so, as workaround in groovy use
//note the square brackets
#MyAnnotationArray( [#MyAnnotation("val1"), #MyAnnotation("val2")] )
public void annotatedMethod()
{
System.out.println("annotated method called");
}
full script (because there were some errors in annotation declaration)
import java.lang.annotation.*
class MyClass
{
//#MyAnnotation(value = "val1")
//#MyAnnotation(value = "val2")
#MyAnnotationArray( [#MyAnnotation("val1"), #MyAnnotation("val2")] )
public void annotatedMethod()
{
System.out.println("annotated method called");
}
public static void main(String... args)
{
MyClass ob = new MyClass()
ob.annotatedMethod()
java.lang.reflect.Method m = ob.getClass().getMethod("annotatedMethod")
List annos = m.getAnnotations()
println("annos = $annos")
}
}
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Repeatable(MyAnnotationArray)
public #interface MyAnnotation
{
String value() default "val0";
}
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotationArray
{
MyAnnotation[] value()
}
also tried against groovy 3.0.0-SNAPSHOT - the result is the same as for 2.4.11
Yes, Groovy has supported "repeatable" annotations for a long time even in Java 5 so long as retention policy was only SOURCE. This is what allows multiple #Grab statements for instance without the outer #Grapes container annotation. Being only retained in SOURCE makes them useful for AST transformations and within the Groovy compiler itself (and other source processors) but not really useful anywhere else. We don't currently support #Repeatable at all but plan to in a future version.

Incorrect stack trace from an exception in a method copied from a groovy shell script

I have a groovy script that defines a method which throws an exception.
Using AST Transformations I generate at compile time a new class.
Then I copy this method from the script to this new class and make the class available at runtime.
When at runtime I create a new object of the new class and call the method in stack trace I can see references to Script1 class instead of the new generated class.
Exception in thread "main" java.lang.RuntimeException
at MyGeneratedClass.myMethod(Script1.groovy:4)
at MyGeneratedClass$myMethod.call(Unknown Source)
at scripttest.ExTest.main(ExTest.groovy:35)
Is there anything I can do to change it so I don't see this Script1.groovy class in stack trace but the new class and line number within it?
My code:
class ExTest {
public static void main(String[] a) {
String script = '''
def myMethod() {
throw new RuntimeException()
}
'''
def config = new CompilerConfiguration()
config.addCompilationCustomizers(new MyCompilerConfiguration())
ClassLoader classLoaderToUse = new GroovyClassLoader()
GroovyShell shell = new GroovyShell(classLoaderToUse, new Binding(), config)
Script parsedScript = shell.parse(script)
def generatedClass = parsedScript.class.fields.find {it.name == 'myGeneratedClassField'}.type
def generated = generatedClass.newInstance()
generated.myMethod()
}
}
class MyCompilerConfiguration extends CompilationCustomizer {
MyCompilerConfiguration() {
super(CompilePhase.CONVERSION)
}
#Override
void call(SourceUnit source, GeneratorContext context, ClassNode currentClassNode) throws CompilationFailedException {
def newClassAst = new AstBuilder().buildFromSpec {
classNode('MyGeneratedClass', ClassNode.ACC_PUBLIC) {
classNode java.lang.Object
interfaces { classNode GroovyObject }
mixins { }
}
}
ClassNode myGeneratedClassNode = newClassAst[0]
source.getAST().addClass(myGeneratedClassNode)
currentClassNode.addField('myGeneratedClassField', Opcodes.ACC_PUBLIC, myGeneratedClassNode, new EmptyExpression())
MethodNode myMethodNode = source.getAST().methods.find {it.name == 'myMethod'}
myGeneratedClassNode.addMethod(myMethodNode.name, Opcodes.ACC_PUBLIC, myMethodNode.returnType, myMethodNode.parameters, myMethodNode.exceptions, myMethodNode.code)
}
}
Your stacktrace is correct, the Script1.groovy:4 you see is not the name of a class, but the name of the file which has generated this class, which is, in your case, a Groovy File.
This name come from the CodeSource instance present in the CompilationUnit associated with the ClassNode. You can change it by using a GroovyCodeSource in methods like GroovyShell.parse or GroovyClassLoader.parseClass, but I think it's a really bad idea ! (security, debugging and other thinks are related to this object)

Spring LDAP Template Usage

Please take a look at the test class below. I am trying to do an LDAP search with Spring LDAP Template. I am able to search and produce a list of entries corresponding to the search criteria without the Spring LDAP template by using the DirContext as shown in the method searchWithoutTemplate(). But when I use a LdapTemplate, I end up with a NPE as shown further below. I am sure I must be missing something. Can someone help please?
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.LdapName;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.DefaultDirObjectFactory;
import org.springframework.ldap.core.support.LdapContextSource;
public class LDAPSearchTest {
//bind params
static String url="ldap://<IP>:<PORT>";
static String userName="cn=Directory Manager";
static String password="password123";
static String bindDN="dc=XXX,dc=com";
//search params
static String base = "ou=StandardUser,ou=XXXCustomers,ou=People,dc=XXX,dc=com";
static String filter = "(objectClass=*)";
static String[] attributeFilter = { "cn", "uid" };
static SearchControls sc = new SearchControls();
public static void main(String[] args) throws Exception {
// sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
sc.setReturningAttributes(attributeFilter);
searchWithTemplate(); //NPE
//searchWithoutTemplate(); //works fine
}
public static void searchWithTemplate() throws Exception {
DefaultDirObjectFactory factory = new DefaultDirObjectFactory();
LdapContextSource cs = new LdapContextSource();
cs.setUrl(url);
cs.setUserDn(userName);
cs.setPassword(password);
cs.setBase(bindDN);
cs.setDirObjectFactory(factory.getClass ());
LdapTemplate template = new LdapTemplate(cs);
template.afterPropertiesSet();
System.out.println((template.search(new LdapName(base), filter, sc,
new AttributesMapper() {
public Object mapFromAttributes(Attributes attrs)
throws NamingException {
System.out.println(attrs);
return attrs.get("uid").get();
}
})));
}
public static void searchWithoutTemplate() throws NamingException{
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url);
//env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, userName);
env.put(Context.SECURITY_CREDENTIALS, password);
DirContext dctx = new InitialDirContext(env);
NamingEnumeration results = dctx.search(base, filter, sc);
while (results.hasMore()) {
SearchResult sr = (SearchResult) results.next();
Attributes attrs = sr.getAttributes();
System.out.println(attrs);
Attribute attr = attrs.get("uid");
}
dctx.close();
}
}
Exception is:
Exception in thread "main" java.lang.NullPointerException
at org.springframework.ldap.core.support.AbstractContextSource.getReadOnlyContext(AbstractContextSource.java:125)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:287)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:237)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:588)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:546)
at LDAPSearchTest.searchWithTemplate(LDAPSearchTest.java:47)
at LDAPSearchTest.main(LDAPSearchTest.java:33)
I am using Spring 2.5.6 and Spring LDAP 1.3.0
A quick scan showed that it's the authenticationSource field of AbstractContextSource that is the culprit. That file includes the following comment on the afterPropertiesSet() method:
/**
* Checks that all necessary data is set and that there is no compatibility
* issues, after which the instance is initialized. Note that you need to
* call this method explicitly after setting all desired properties if using
* the class outside of a Spring Context.
*/
public void afterPropertiesSet() throws Exception {
...
}
That method then goes on to create an appropriate authenticationSource if you haven't provided one.
As your test code above is most definitely not running within a Spring context, and you haven't explicitly set an authenticationSource, I think you need to edit your code as follows:
...
cs.setDirObjectFactory(factory.getClass ());
// Allow Spring to configure the Context Source:
cs.afterPropertiesSet();
LdapTemplate template = new LdapTemplate(cs);

Cannot dynamically change or add methods in a class using GroovyClassLoader

I try to dynamically change and add methods of a class defined in a groovy script from another groovy script but cannot figure out why it works if I use the classname directly in .metaClass. but not if I load the class using the GroovyClassLoader(which I need to do!).
In one file 'MyTest.groovy' I have
class MyTest {
public void setUp() {
println "SET UP"
}
public void tearDown() {
println "TEAR DOWN"
}
public void testA() {
println "testA"
}
}
and another file 'suite.groovy' contains
#!/usr/bin/env groovy
public class MyTestSuite {
// For debug
public static printClassLoader(Class cls) {
ClassLoader loader = cls.classLoader
while (loader) {
println loader.class
println loader.URLs.join("\n")
println "\n\n"
loader = loader.parent
}
}
public static void suite() {
// First method to define my class (change/addition of methods works)
//Class testClass = MyTest
// Second way to define my class (change/addition of methods doesn't work)
ClassLoader parent = MyTestSuite.class.getClassLoader();
GroovyClassLoader gcl = new GroovyClassLoader(parent);
Class testClass = gcl.parseClass(new File("MyTest.groovy"));
printClassLoader(testClass)
testClass.metaClass.setUp = {-> println "I'm your new setUp()" ;}
testClass.metaClass.newTest = {-> println "I'm your new newTest()" ; }
}
}
MyTestSuite.suite()
MyTest aTest = new MyTest()
aTest.setUp()
aTest.newTest()
With the first method I get the expected result:
I'm your new setUp()
I'm your new newTest()
But with the second one I get
SET UP
Caught: groovy.lang.MissingMethodException: No signature of method: MyTest.newTest() is applicable for argument types: () values: []
Possible solutions: testA(), getAt(java.lang.String), wait(), inspect(), every()
at suite.run(suite.groovy:34)
Interestingly modifying an existing method doesn't work but there is no exception but trying to add a new one throws one.
I reckon it has to do something with the class loaders used but couldn't figure what exactly and what to change!
For the first version here are the class loaders called:
class groovy.lang.GroovyClassLoader$InnerLoader
class groovy.lang.GroovyClassLoader
class org.codehaus.groovy.tools.RootLoader
class sun.misc.Launcher$AppClassLoader
class sun.misc.Launcher$ExtClassLoader
For the second version:
class groovy.lang.GroovyClassLoader$InnerLoader
class groovy.lang.GroovyClassLoader
class groovy.lang.GroovyClassLoader$InnerLoader
class groovy.lang.GroovyClassLoader
class org.codehaus.groovy.tools.RootLoader
class sun.misc.Launcher$AppClassLoader
class sun.misc.Launcher$ExtClassLoader
Any idea welcome!
Franck
The new GroovyClassLoader is not the Groovy classloader of the current thread.
It will be disposed after the suite() method finishes - along with its own Class and MetaClass associations.
However, this works:
Class testClass = gcl.parseClass(new File("MyTest.groovy"));
testClass = Class.forName(testClass.getName())

Resources