Send arguments to Test Library through Remote Library

519 views
Skip to first unread message

Alejandro Serrano

unread,
Feb 28, 2014, 1:52:18 PM2/28/14
to robotframe...@googlegroups.com
Hi,

Not sure if this would be a trivial question but here I go. I have created a Java Library which receives some arguments. Taking my library into use as follows, it just works fine.

Importing my test library
-------------------------------------------
| Setting | Value         | Value | Value |
-------------------------------------------
| Library | MyJavaLibrary | arg1  | arg2  |
-------------------------------------------

However, I'm trying to use my java library through Remote Library. (This is my first time using Remote Library.)

-------------
| Test Data |
-------------
------------------
| RobotFramework |
------------------
------------------
| Remote Library |
------------------
       |
       | XML-RPC
       |
-----------------
| Remote Server | # jrobotremoteserver
-----------------
-----------------
| MyJavaLibrary | # MyJavaLibrary | arg1 | arg2 |
-----------------
---------------------
| System Under Test |
---------------------


I did some experiments using my Java Library without arguments and everything is working fine.

Importing Remote Library 
---------------------------------------------------------------------------
| Setting | Value    | Value                  | Value     | Value         |
---------------------------------------------------------------------------
| Library | Remote   | http://127.0.0.1:8270  | WITH NAME | MyJavaLibrary |
---------------------------------------------------------------------------

But I'm getting stuck trying to send the arguments needed by my library through the Remote Library.

I tried to send the arguments as follows:
-----------------------------------------------------------------------------------------------
| Setting | Value   | Value                  | Value | Value | Value     | Value              |
-----------------------------------------------------------------------------------------------
| Library | Remote  | http://127.0.0.1:8270  | arg1  | arg2  | WITH NAME | MyJavaLibrary      |
-----------------------------------------------------------------------------------------------

Getting the following error:
- Test Library 'Remote' expected 0 to 1 arguments, got 3.


Could you please explain me how can I send the arguments to my java lib using the Remote Library?
Does it need to be done programmatically in java or python side?

Any help would be appreciated.
Thanks,
Alejandro.

Kevin O.

unread,
Feb 28, 2014, 6:23:56 PM2/28/14
to robotframe...@googlegroups.com
Since the remote server has already instantiated the library, there is no way to pass in arguments with the current version of the remote library API.
jrobotremoteserver will always instantiate your library with no arguments.
If there are no keywords that perform the same action as using library arguments, you can subclass the library and make the default constructor invoke some other constructor with the arguments you want (example below).
I designed the server to not allow passing in a library instance in case of future enhancements that may involve spawning new instances of libraries. Let me know if you think I should re-think that.
The Python server allows you to pass in an instance.
I was thinking about having a way to control the server from a library. This would allow one library to create other libraries with arguments at runtime. A built-in remote library would make this work out of the box.
Let me know if that would be helpful.

Here is an example of creating an anonymous class that changes the default constructor to call another constructor with an argument:
        ...
        class MyMap extends HashMap {
            public MyMap() {
                super(5);
            }
        }
        server.addLibrary(MyMap.class)

Alejandro Serrano

unread,
Feb 28, 2014, 9:28:04 PM2/28/14
to robotframe...@googlegroups.com

Hi Kevin,

Now I have a better understanding of why the Remote Library is designed in that way.

I'm going to change a little bit the implementation of my java library, since I am extending from AnnotationLibrary and give it a try as per your suggestion.

Thank you very much!
Alejandro.

Pekka Klärck

unread,
Mar 1, 2014, 4:56:00 PM3/1/14
to ombre42 ., robotframework-users
2014-03-01 1:23 GMT+02:00 Kevin O. <korm...@gmail.com>:
> Since the remote server has already instantiated the library, there is no
> way to pass in arguments with the current version of the remote library API.
> jrobotremoteserver will always instantiate your library with no arguments.
> If there are no keywords that perform the same action as using library
> arguments, you can subclass the library and make the default constructor
> invoke some other constructor with the arguments you want (example below).
> I designed the server to not allow passing in a library instance in case of
> future enhancements that may involve spawning new instances of libraries.
> Let me know if you think I should re-think that.
> The Python server allows you to pass in an instance.

Kevin is absolutely correct about everything above. Just want to note
that the Python server requires passing library instances or modules,
it never instantiates the library itself.

The main reason for the current behavior is that there hasn't been big
enough need to add support for passing library arguments and thus the
remote API doesn't support it. Related to this, remote libraries are
always considered to have a global scope by Robot Framework and thus
they get no notification when tests/suites start/end. If there's
strong enough interest, we can start discussing how to extend the API
so that library arguments and scopes could be supported.

Cheers,
.peke
--
Agile Tester/Developer/Consultant :: http://eliga.fi
Lead Developer of Robot Framework :: http://robotframework.org

Kevin O.

unread,
Mar 3, 2014, 11:46:33 PM3/3/14
to robotframe...@googlegroups.com, ombre42 .
I certainly did not mean to imply the remote library API is deficient in this regard.

Alejandro,
Like Pekka said, remote libraries have a global scope (well actually more than global scope because the library instance may exist across different executions). Ideally, globally scoped libraries should have a way to change state or configure the library using keywords rather than library initialization arguments.

So I obviously need to add a putLibrary(Object library, String path) method in the Java server.
I am going to remove the existing putLibrary(Class<?> libraryClass, String path) as it does not seem to add any value. It was never in a released version (the old methods are called addLibrary and are deprecated).

Alejandro Serrano

unread,
Mar 4, 2014, 9:59:26 AM3/4/14
to robotframe...@googlegroups.com, ombre42 .

Kevin/Pekka,

Thanks for your comments. Now that I'm getting more familiar with this concept of remote libraries, I'm understanding better the design of current remote library API.

I'm going to change the approach and create a keyword to setup my test environment and configure the library rather than send the arguments to the java library constructor.

Just as a closure note I would like to show you what I was trying to do...

The reason I was trying to do that is because I have created my own logging configuration class within my project using the Java Logging API. I want to send my log files to the temp directory created by RIDE when a test execution is performed. One of the arguments I was trying to get is the ${OUTPUTDIR} variable. In this class, I am creating "on the fly" my own logging.properties file to configure the Java LogManager instead of using the default file provided by Java at %JAVA_HOME%\jre\lib\logging.properties.

Whenever you want to use the Java Logging API you need to run your Java app (in this case my library) with the jvm argument -Djava.util.logging.config.file=MyJavaLibrary.properties
(Here pointing to my own .properties file)
For example:
MyJavaLibrary.jar -Djava.util.logging.config.file=MyJavaLibrary.properties

However, I found the way to do it without sending the jvm argument to MyLibrary.jar but it requires to initialize and create my configuration when a new instance of my library is created. I thought the constructor of MyJavaLibrary was the properly way to do it.

I was tying to set up the log output directory in my properties file as follows:
java.util.logging.FileHandler.pattern=RIDEOutputDir\MyJavaLibrary.%u-%g.log

This is an example of MyJavaLibrary class

/**
 * @author Alejandro Serrano
 */
public class MyJavaLibrary extends AnnotationLibrary {
    /*
     * Test library scope.
     */
    public static final String ROBOT_LIBRARY_SCOPE = "GLOBAL";
    /*
     * Test library Documentation.
     * FIXME: Define the init library documentation...
     */
    private static final String INIT_LIBRARY_DOCUMENTATION = "TBD......";
    /*
     * TODO: Define the intro library documentation....
     */
    private Logger logger = Logger.getLogger(getClass().getSimpleName());
    private static final int PORT = 8270;
    
    /**
     * MyJavaLibrary no-arg constructor. Invokes its own overloaded 
     * constructor that takes the outputDir and arg2, arg3... Strings needed to
     * initialize the Java Application and MyJavaLibrary
     * logging configuration.
     */
    public MyJavaLibrary(){
        this("", "");
    }
    
    /**
     * MyJavaLibrary constructor.
     *  - Specifies under which packages the keywords are contained.
     *  - Initializes the library logging configuration.
     */
    public MyJavaLibrary(final String outputDir, final String arg2){
        super("com/myOrg/systemUnderTest/keyword/**/*.class");
        logger.info("MyJavaLibrary keywords registered through AnnotationLibrary.");
        /*
         *  Validations for output dir goes here
         */
        
        /*
         * My logging configuration object....
         */
        LoggingConfiguration libraryLogger = new LoggingConfiguration(outputDir);
        libraryLogger.initializeLogging();
        /*
         * Important stuff to save the arg2, arg3, arg4... as an initial state and setup my test environment goes here
         */
    }
    
    /**
     * Getting keyword documentation.
     * Overriding this method including the equals comparison for '__init__' to provide
     * the library documentation.
     */
    @Override
    public String getKeywordDocumentation(String keywordName) {
        if (keywordName.equals("__init__")){
            return INIT_LIBRARY_DOCUMENTATION;
        }
        return super.getKeywordDocumentation(keywordName);
    }

    /*
     * Important code goes here
     * ....
     * ....
     * ....
     */
    
    /**
     * Starts jrobotremoteserver needed to interact the RF Remote library.
     * The RF Remote library interacts with actual library implementation
     * through the java remote server using a simple remote protocol on top
     * of an XML-RPC channel.
     */
    public static void main(String[] args) throws Exception{
        RemoteServer.configureLogging();
        RemoteServer server = new RemoteServer();
        server.addLibrary(MyJavaLibrary.class, PORT);
        server.start();
    }
}

I could initialize the logging configuration in the main method. However, I'm trying to build my Library to work either way in a Remote mode and in a "Normal" mode.
I'm going to figure out how to initialize my logging configuration in a different way.

Thank you very much for teaching me the concept of the remote libraries.
Alejandro.

Kevin O.

unread,
Mar 4, 2014, 1:22:25 PM3/4/14
to robotframe...@googlegroups.com, ombre42 .
Interesting. This log is not for troubleshooting the library right?
One solution would be to have a keyword in your Java library Get Log And Clear that returns the contents of the log file as a giant string.
If you are following best practices than you should be importing your remote library through a resource file and not directly from a suite file.
In that resource file you could put a Save And Clear Log user keyword that calls Get Log And Clear and saves the log contents to ${OUTPUTDIR}/MyJavaLibraryLog.txt.
This would work locally and remotely.
Unfortunately with remote libraries, there is sometimes a need to have local keywords as well remote ones.
I forgot to mention that with remote libraries is a good idea to have a reset keyword that resets the state of the library regardless of how it was used before (previous test could have failed and left it in a problematic state).

Kevin

Alejandro Serrano

unread,
Mar 5, 2014, 10:51:32 AM3/5/14
to robotframe...@googlegroups.com, ombre42 .

Log is going to be used to register additional information about the current state of the application on certain points of the execution. Since the application is running in JavaFX, some of the actions in my keywords need to be executed into the JavaFX Application thread. I would like to log specific information that will help Development Team to investigate the root cause of any bug found with Automation.

Yes, I am using a resource file to import the remote library and setup all my global variables. I will try your suggestion.

Good to know the reset keyword approach! :)

Additionally, under the direction and guidance of my Manager, I have created a very simple library to drive test automation over JavaFX applications using JemmyFX. It's something similar to SwingLibrary but very very very simple. Hopefully, we can share it with the community in the future, and improve it. This JavaFX library is not as complex as SwingLibrary but I think is a good start.

"MyJavaLibrary" is already using my JemmyFXLibrary.

Alejandro.
Reply all
Reply to author
Forward
0 new messages