Reputation: 408
I have a python document running in bokeh server with bokeh serve view_server_so.py --show
. The webpage is immediately opened in a browser tab.
For testing purposes I am using Pyro to allow remote access to some of the objects / methods running in the bokeh server.
My server testscript creates just one button and one method (exposed to remote control), bokeh serves the webpage on http://localhost:5006/view_server_so
.
The button is a Toggle button, each time the button is pressed its active state alternates between True
and False
, and its color changes.
# view_server_so.py
# This script shall be started from the command line with
# bokeh serve view_server_so.py --show
from bokeh.layouts import layout, row
bokeh.models import Toggle
from bokeh.io import curdoc
import os
import Pyro4
import socket
import subprocess
import threading
# The layout used in the html-page
class View():
def __init__(self):
self.document = curdoc()
self.btn_task = Toggle(label="Press me",
button_type="success",
css_classes=["btn_task"])
self.layout = layout(row(self.btn_task))
@Pyro4.expose
def get_btn_task_active_state(self):
# This method is enabled for remote control
# The btn_task changes its active state each time it is pressed (bool)
print('active state: {}'.format(self.btn_task.active))
return self.btn_task.active
# As the script is started with 'bokeh serve',
# bokeh has control of the main event loop.
# To enable Pyro to listen for client requests for the object view,
# and its exposed method,
# the Pyro event loop needs to run in its own thread.
class PyroDaemon(threading.Thread):
def __init__(self, obj):
threading.Thread.__init__(self)
self.obj=obj
self.started=threading.Event()
print('PyroDaemon.__init__()')
def run(self):
daemon=Pyro4.Daemon()
obj = self.obj
self.uri=daemon.register(obj,"test")
self.started.set()
print('PyroDaemon.run()')
daemon.requestLoop()
view = View()
print('view created')
# starting a Pyro name server
hostname = socket.gethostname()
print('hostname: {}'.format(hostname))
try:
print('try Pyro4.locateNS()')
name_server=Pyro4.locateNS()
except Pyro4.errors.NamingError:
print('except Pyro4.errorsNamingError')
args = ['python', '-m', 'Pyro4.naming', '-n', hostname]
p = subprocess.Popen(args)
name_server=Pyro4.locateNS()
print('Nameserver is started')
# create a pyro daemon with object view, running in its own worker thread
pyro_thread=PyroDaemon(view)
pyro_thread.setDaemon(True)
pyro_thread.start()
pyro_thread.started.wait()
print('Daemon is started')
# The object view is registered at the Pyro name server
name_server.register('view', pyro_thread.uri, metadata = {'View'})
print('view is registered')
view.document.add_root(view.layout)
Now I have a second testscript. After some setup for the remote object, it simply calls several times the method get_btn_task_active_state()
and prints the result. When between the calls the button is clicked in the browser, the active state switches and is correctly printed.
import Pyro4
import time
# looking for the Pyro name server created in view_server_so.py
nameserver=Pyro4.locateNS(broadcast = True)
# get the URI (universal resource identifier)
uris = nameserver.list(metadata_all = {'View'})
# create a proxy object that interacts (remote control)
# with the remote object 'view'
view_rc = Pyro4.Proxy(uris['view'])
for i in range(3):
time.sleep(3)
# change the state manually: click on the button
print('state: {}'.format(view_rc.get_btn_task_active_state()))
# prints
# state: False
# state: True
# state: False
As manual testing gets tedious, I want to automate the manual clicks to the button. So I am adding webdriver support, look up the button in the webpage, and have some automated clicks and the calls to get_btn_task_active_state()
as before.
import Pyro4
from selenium import webdriver
import socket
import time
# looking for the Pyro name server created in view_server_so.py
nameserver=Pyro4.locateNS(broadcast = True)
# get the URI (universal resource identifier)
uris = nameserver.list(metadata_all = {'View'})
# create a proxy object that interacts (remote control)
# with the remote object 'view'
view_rc = Pyro4.Proxy(uris['view'])
# use the Chrome webdriver
driver = webdriver.Chrome()
# open a Chrome Browser and the given webpage
driver.get("http://localhost:5006/view_server_so")
time.sleep(1)
# Find the button
btn_task = driver.find_element_by_class_name("btn_task")
for i in range(3):
time.sleep(1)
print('state: {}'.format(view_rc.get_btn_task_active_state()))
btn_task.click()
# prints
# state: False
# state: False
# state: False
#
# but should alternate between False and True
An webdriver controlled browser opens, I can see the color of the button change visually as it is automatically clicked, but the active state of the button does not seems to change any more.
What changes would be necessary, so that the automated script gives the same results as the manual testing?
Upvotes: 0
Views: 227