How to combine "multiprocessing" with robotframework

1,559 views
Skip to first unread message

Mykhailo Poliarush

unread,
Mar 31, 2012, 8:38:54 AM3/31/12
to robotframework-users
I need to build library that start and stop server. Once process is up
and running it will be in background so during the test steps some
keywords can access to server.

I've built following code that perfectly works in pure python but when
I call method as keywords in RF I got issue

My original code tested in python:
===========
from soaplib.wsgi_soap import SimpleWSGISoapApp
from soaplib.service import soapmethod
from soaplib.serializers.clazz import ClassSerializer
from soaplib.serializers.primitive import String, Integer, Array,
DateTime
import multiprocessing, time, signal
from robot.api import logger
import logging

class MockedObject(SimpleWSGISoapApp):
@soapmethod(String, _returns=String)
def mocked_method(self,id):
text = """\
<request name="dbcall">
<procedure name="change_services">
<action schema="dbo">pkg_sim_portal.change_services</action>
<parameter name="pErrMsg" direction="output" type="VARCHAR2"></
parameter>
<parameter name="pImmediate" direction="input" type="FLOAT">0</
parameter>
<parameter name="pMVNORef" direction="input" type="VARCHAR2">MGE</
parameter>
<parameter name="pPhoneNo" direction="input" type="VARCHAR2">1231</
parameter>
<parameter name="pServices" direction="input" type="VARCHAR2">8933</
parameter>
</procedure>
</request>"""
return text

class MockWebservice(object):
def _run_server(self):
try:
from wsgiref.simple_server import make_server
server = make_server('localhost', 7789,MockedObject())
server.serve_forever()
print "server started"
except ImportError:
print "Error: example server code requires Python >= 2.5"


class MockRunner(object):
mockedWebservice = MockWebservice()
def start_server(self):
self.p =
multiprocessing.Process(target=self.mockedWebservice._run_server)
self.p.start()

def stop_server(self):
self.p.terminate()

if __name__ == '__main__':
m = MockRunner()
m.start_server()
for i in range(10):
time.sleep(2)
if i == 7:
m.stop_server()
print i
m.stop_server()

Library that I've done:

library
=========
from soaplib.wsgi_soap import SimpleWSGISoapApp
from soaplib.service import soapmethod
from soaplib.serializers.clazz import ClassSerializer
from soaplib.serializers.primitive import String, Integer, Array,
DateTime
import multiprocessing, time, signal
from robot.api import logger
import logging

class MockedObject(SimpleWSGISoapApp):
@soapmethod(String, _returns=String)
def mocked_method(self,id):
text = """\
<request name="dbcall">
<procedure name="change_services">
<action schema="dbo">pkg_sim_portal.change_services</action>
<parameter name="pErrMsg" direction="output" type="VARCHAR2"></
parameter>
<parameter name="pImmediate" direction="input" type="FLOAT">0</
parameter>
<parameter name="pMVNORef" direction="input" type="VARCHAR2">MGE</
parameter>
<parameter name="pPhoneNo" direction="input" type="VARCHAR2">1231</
parameter>
<parameter name="pServices" direction="input" type="VARCHAR2">8933</
parameter>
</procedure>
</request>"""
return text

class MockedWebserviceServer(object):
def _run_server(self):
logger.warn("in MockedWebserviceServer")
try:
from wsgiref.simple_server import make_server
server = make_server('localhost', 7789,MockedObject())
server.serve_forever()
print "server started"
except ImportError:
print "Error: example server code requires Python >= 2.5"

class MockRunner(object):
mocked_webservice = MockedWebserviceServer()
def start_server(self):
self.p =
multiprocessing.Process(target=self.mocked_webservice._run_server)
self.p.start()

def stop_server(self):
self.p.terminate()


wrapper
=========
from mock import MockRunner

__version__ = '0.1'
__author__ = 'Mykhailo Poliaruh'

class MockLibrary(MockRunner):
"""
MockWebservice
"""
ROBOT_LIBRARY_SCOPE = 'GLOBAL'



My test case
=====
*** Settings ***
Library MockLibrary

*** Test Cases ***
test
Start Server
Sleep 5 seconds
Stop Server


Issue I got
=========
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "c:\Program Files (x86)\python27\lib\multiprocessing
\forking.py", line 373, in main
prepare(preparation_data)
File "c:\Program Files (x86)\python27\lib\multiprocessing
\forking.py", line 488, in prepare
'__parents_main__', file, path_name, etc
File "c:\Program Files (x86)\python27\lib\site-packages\robot
\run.py", line 322, in <module>
import pythonpathsetter # running robot/run.py as a script
ImportError: No module named pythonpathsetter

Please help me out to incorporate my code correctly to RF.

Mykhailo Poliarush

unread,
Mar 31, 2012, 8:49:23 AM3/31/12
to robotframework-users
It's definitely because I start new process with self.p.start() where
robot module are not in path.
But I don't know how to start it right in background so it's not
affected robot process.

Mikko Korpela

unread,
Apr 2, 2012, 1:46:58 AM4/2/12
to pol...@gmail.com, robotframework-users
Hi,

I think the problem is that Robot Framework has some internal global
state (related to logging in this case). And when you are jumping over
a process boundary the internal state is totally different for the
other process.

The safest way in my opinion would be not to import anything from
robot in the module your going to run in the other process.
You could also use threading and then the shared state would be "OK"
.. but only if nothing CPU intensive is required (because of the GIL).

Kind Regards,
Mikko Korpela

> --
> You received this message because you are subscribed to the Google Groups "robotframework-users" group.
> To post to this group, send email to robotframe...@googlegroups.com.
> To unsubscribe from this group, send email to robotframework-u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/robotframework-users?hl=en.
>

--
Mikko Korpela

Mykhailo Poliarush

unread,
Apr 2, 2012, 4:56:01 AM4/2/12
to Mikko Korpela, robotframework-users
Thanks for help. I did try with threads and it works but I can't correctly stop thread so I just put thread as deamon and it's killed when test is finished. Solution is following:

    def start_server(self, host='localhost', port=7788):
        '''
        Start server with defined `host` and `port`. Server will start in background.
        So once you started server you can do request to webservice.
        
        `start_server` can take two optional parameters
        it sets to host='localhost', port=7788 by default
        
        *Note:* you can easy change response body without server restart by calling keyword `changed_message_body`
        
        _Example:_
        | changed message body |    123 |     | 
        | Start Server  |   localhost |    8890 | 
        | Sleep |    1 seconds    | | 
        | test webservice by call |   |      
        | Sleep |    1 seconds    | | 
        | changed message body |    321 | |      
        | Sleep |     2 seconds    | | 
        | test webservice by call |    |     
        | Stop Server | |        |
        '''
        self._host, self._port = host, port
        self.mocked_webservice._set_host_and_port(host, port)
        thread = threading.Thread(target=self.mocked_webservice._start_server)
        thread.daemon = True
        thread.start()

    def stop_server(self):
        '''
        Stop server started by keyword `start_server`
        '''
        self.mocked_webservice._stop_server()

------------------------------
Mykhailo Poliarush

Mikko Korpela

unread,
Apr 2, 2012, 6:04:38 AM4/2/12
to Mykhailo Poliarush, robotframework-users
Have you tried this one:
http://www.gossamer-threads.com/lists/python/python/886482

--
Mikko Korpela

Mykhailo Poliarush

unread,
Apr 2, 2012, 3:42:08 PM4/2/12
to Mikko Korpela, robotframework-users
Hi Mikko,

That works great. Thank you for suggestion.

Thanks, 
------------------------------
Mykhailo Poliarush
skype: mykhailo.poliarush | +380501716246linkedin
 | twitter 
http://poliarush.com | rss
http://automated-testing.info | rss | linkedin | twitter 
 | facebook | vkontakte
Reply all
Reply to author
Forward
0 new messages