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

Remote library calling run_keyword provides object as string representation #4874

Closed
HackXIt opened this issue Sep 20, 2023 · 2 comments
Closed

Comments

@HackXIt
Copy link

HackXIt commented Sep 20, 2023

I have a remote library using our own Remote Library Interface implementation in C#.

Given a testcase like this:

*** Variables ***
@{LIST_INT32}           ${1}    ${2}    ${3}
*** Test Cases ***
List Int32 Conversion
    TESTLIB.ListInt32 ParameterType    ${LIST_INT32}
    ${converted_list}=    TESTLIB.ListInt32 ParameterType    ${LIST_INT32}
    Lists Should Be Equal    ${converted_list}    ${LIST_INT32}

Then the provided argument ${LIST_INT32} will be passed as a string representation of the object, in our case: "[1, 2, 3]"

I would expect that robot framework calling run_keyword() would provide such variables as-is, which is also the case according to the documentation:

When a scalar variable is used alone without any text or other variables around it, like in ${GREET} above, the variable is replaced with its value as-is and the value can be any object. If the variable is not used alone, like ${GREER}, ${NAME}!! above, its value is first converted into a string and then concatenated with the other data.

I am unsure why the invocation in the code of Remote.py does this.

I've done a very simple comparison using the XML-RPC client of python directly:

import xmlrpc.client

intList = [1, 2, 3, 4, 5]
# I tested all other types as well, I've left them out for simplicity

def execute_keyword(uri, keyword, *args):
    with xmlrpc.client.ServerProxy(uri, encoding='UTF-8', use_builtin_types=True, verbose=True) as proxy:
        print(proxy)
        try:
            print(proxy.run_keyword(keyword, *args))
        except xmlrpc.client.Fault as err:
            print(err)

func_name = f'ListInt32 ParameterType'
execute_keyword('http://localhost:8270/Testcenter/RobotFramework/Test/KeywordLibrary/TestKeywords', func_name, [intList])

This simple comparison provides the object as-is and doesn't convert the object to a string representation.
It's the same keyword being called.
I've set a breakpoint in my XmlRpcService.
Calling the keyword from my simple xml-rpc client in python, I can see the argument provided as this:
grafik

When the keyword is called through robot framework with the scalar variable, I can see the argument provided as this:
1925a427b59a59f0132bb76b51030ce7ffc84e6b

In my eyes, this is a bug in robot framework, as somehow in the Remote library implementation the testcase variable is not provided as-is.


You can see that I've used an asterisk in this invocation, to provide the argument list as-is.
This should be equal/similar to the implementation of Remote.py:

def run_keyword(self, name, args, kwargs):
        with self._server as server:
            run_keyword_args = [name, args, kwargs] if kwargs else [name, args]
            try:
                return server.run_keyword(*run_keyword_args)
            except xmlrpc.client.Fault as err:
                message = err.faultString
            except socket.error as err:
                message = f'Connection to remote server broken: {err}'
            except ExpatError as err:
                message = (f'Processing XML-RPC return value failed. '
                           f'Most often this happens when the return value '
                           f'contains characters that are not valid in XML. '
                           f'Original error was: ExpatError: {err}')
            raise RuntimeError(message)

I am unsure what is done differently to the argument list in robot framework.

@HackXIt
Copy link
Author

HackXIt commented Sep 20, 2023

Just for insight, this is our remote library interface implementation for run_keyword for the XmlRpcService:

public XmlRpcStruct run_keyword(string friendlyName, object[] args)
    {
        // I directly checked the values of args here, before anything was done
        Logger.Debug($"XmlRpc method call - run_keyword: {friendlyName} with args [{string.Join(",", args)}]");
        XmlRpcStruct xmlRpc;
        try
        {
            var typename = _threadKeywordType[Thread.CurrentThread.ManagedThreadId];
            var keyword = _keywordManager.GetKeyword(typename, friendlyName);
            // Pre-process arguments for conversion of arrays to lists/dictionaries (SupportedTypes)
            args = PreProcess(keyword.KeywordMethod, args);
            var result = _keywordManager.RunKeyword(keyword, args);
            result.KeywordReturn = PostProcess(keyword.KeywordMethod, result.KeywordReturn);
            Logger.Debug(result.ToString());
            xmlRpc = XmlRpcBuilder.FromKeywordResult(result);
        }
        catch (Exception e)
        {
            Logger.Error($"Exception in method - run_keyword {friendlyName}: {e.Message}\n{e.StackTrace}");
            throw new XmlRpcFaultException(1, e.Message);
        }
        return xmlRpc;
    }

@HackXIt
Copy link
Author

HackXIt commented Sep 21, 2023

I have noticed this error occurs on my remote server implementation, due to the types that are provided to the robot framework in the library information.

For dictionaries and lists of specific type other than object I was very stubborn and provided the fallback type string. It was an oversight of mine, since I've forgotten to adjust my RobotTypeConverter function, which just checks the type and writes the appropriate type-string for robot framework according to argument-conversion.
The fallback value was causing the issue.

It also explains the difference in my comparison, since in my own simple xml-rpc client in python, there was no argument conversion and no request for library information. I simply called the keyword directly.
Robot framework obviously is a lot more sophisticated than that, and I didn't know that my own provided library information could produce such a false-positive.

Some details about this can be seen in the slack-conversation:
https://robotframework.slack.com/archives/C3C28F9DF/p1695047126359479

Also, my forum post will be solved by closing this issue:
https://forum.robotframework.org/t/arguments-provided-to-remote-library-interface-do-not-follow-xml-rpc-specification/6218/13

I'm closing the ticket as it has been resolved.

@HackXIt HackXIt closed this as completed Sep 21, 2023
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

1 participant