async def test_metadata(ManagedServerLoop) -> None: application = Application(metadata=dict(hi="hi", there="there")) with ManagedServerLoop(application) as server: meta_url = url(server) + 'metadata' meta_resp = await http_get(server.io_loop, meta_url) meta_json = json.loads(meta_resp.buffer.read().decode()) assert meta_json == { 'data': { 'hi': 'hi', 'there': 'there' }, 'url': '/' } def meta_func(): return dict(name='myname', value='no value') application1 = Application(metadata=meta_func) with ManagedServerLoop(application1) as server: meta_url = url(server) + 'metadata' meta_resp = await http_get(server.io_loop, meta_url) meta_json = json.loads(meta_resp.buffer.read().decode()) assert meta_json == { 'data': { 'name': 'myname', 'value': 'no value' }, 'url': '/' }
async def test_server_applications_callable_arg(ManagedServerLoop) -> None: def modify_doc(doc): doc.title = "Hello, world!" with ManagedServerLoop(modify_doc, port=0) as server: await http_get(server.io_loop, url(server)) session = server.get_sessions('/')[0] assert session.document.title == "Hello, world!" with ManagedServerLoop({"/foo": modify_doc}, port=0) as server: await http_get(server.io_loop, url(server) + "foo") session = server.get_sessions('/foo')[0] assert session.document.title == "Hello, world!"
def test_log_stats(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application) as server: server._tornado._log_stats() session1 = pull_session(session_id='session1', url=url(server), io_loop=server.io_loop) session2 = pull_session(session_id='session2', url=url(server), io_loop=server.io_loop) server._tornado._log_stats() session1.close() session2.close() server._tornado._log_stats()
async def test_get_sessions(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application) as server: server_sessions = server.get_sessions('/') assert len(server_sessions) == 0 await http_get(server.io_loop, url(server)) server_sessions = server.get_sessions('/') assert len(server_sessions) == 1 await http_get(server.io_loop, url(server)) server_sessions = server.get_sessions('/') assert len(server_sessions) == 2 server_sessions = server.get_sessions() assert len(server_sessions) == 2 with pytest.raises(ValueError): server.get_sessions("/foo") with ManagedServerLoop({ "/foo": application, "/bar": application }) as server: await http_get(server.io_loop, url(server) + "foo") server_sessions = server.get_sessions('/foo') assert len(server_sessions) == 1 server_sessions = server.get_sessions('/bar') assert len(server_sessions) == 0 server_sessions = server.get_sessions() assert len(server_sessions) == 1 await http_get(server.io_loop, url(server) + "foo") server_sessions = server.get_sessions('/foo') assert len(server_sessions) == 2 server_sessions = server.get_sessions('/bar') assert len(server_sessions) == 0 server_sessions = server.get_sessions() assert len(server_sessions) == 2 await http_get(server.io_loop, url(server) + "bar") server_sessions = server.get_sessions('/foo') assert len(server_sessions) == 2 server_sessions = server.get_sessions('/bar') assert len(server_sessions) == 1 server_sessions = server.get_sessions() assert len(server_sessions) == 3
async def test__include_headers(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application, include_headers=['Custom']) as server: sessions = server.get_sessions('/') assert 0 == len(sessions) response = await http_get(server.io_loop, url(server), headers={'Custom': 'Test'}) html = response.body token = extract_token_from_json(html) payload = get_token_payload(token) assert 'headers' in payload assert payload['headers'] == {'Custom': 'Test'}
async def test__exclude_cookies(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application, exclude_cookies=['custom']) as server: sessions = server.get_sessions('/') assert 0 == len(sessions) response = await http_get(server.io_loop, url(server), headers={'Cookie': 'custom = test ; custom2 = test2'}) html = response.body token = extract_token_from_json(html) payload = get_token_payload(token) assert 'cookies' in payload assert payload['cookies'] == {'custom2': 'test2'}
async def test__request_in_session_context(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application) as server: response = await http_get(server.io_loop, url(server) + "?foo=10") html = response.body sessionid = extract_sessionid_from_json(html) server_session = server.get_session('/', sessionid) server_doc = server_session.document session_context = server_doc.session_context # do we have a request assert session_context.request is not None
async def test__request_in_session_context_has_arguments(ManagedServerLoop): application = Application() with ManagedServerLoop(application) as server: response = await http_get(server.io_loop, url(server) + "?foo=10") html = response.body sessionid = extract_sessionid_from_json(html) server_session = server.get_session('/', sessionid) server_doc = server_session.document session_context = server_doc.session_context # test if we can get the argument from the request assert session_context.request.arguments['foo'] == [b'10']
async def test__no_generate_session_doc(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application, generate_session_ids=False) as server: sessions = server.get_sessions('/') assert 0 == len(sessions) with (pytest.raises(HTTPError)) as info: await http_get(server.io_loop, url(server)) assert 'No bokeh-session-id provided' in repr(info.value) sessions = server.get_sessions('/') assert 0 == len(sessions)
async def test__exclude_headers(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application, exclude_headers=['Connection', 'Host']) as server: sessions = server.get_sessions('/') assert 0 == len(sessions) response = await http_get(server.io_loop, url(server)) html = response.body token = extract_token_from_json(html) payload = get_token_payload(token) assert 'headers' in payload assert payload["headers"].get("Accept-Encoding") == "gzip"
async def test__reject_no_token_websocket(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application) as server: sessions = server.get_sessions('/') assert 0 == len(sessions) await http_get(server.io_loop, url(server)) sessions = server.get_sessions('/') assert 1 == len(sessions) ws = await websocket_open(server.io_loop, ws_url(server), subprotocols=["foo"]) assert await ws.read_queue.get() is None
async def test__autocreate_session_doc(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application) as server: sessions = server.get_sessions('/') assert 0 == len(sessions) response = await http_get(server.io_loop, url(server)) html = response.body sessionid = extract_sessionid_from_json(html) sessions = server.get_sessions('/') assert 1 == len(sessions) assert sessionid == sessions[0].id
async def test__reject_unsigned_session_header_doc(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application, sign_sessions=True, secret_key='bar') as server: sessions = server.get_sessions('/') assert 0 == len(sessions) expected = 'foo' with (pytest.raises(HTTPError)) as info: await http_get(server.io_loop, url(server), headers={"Bokeh-Session-Id": expected}) assert 'Invalid token or session ID' in repr(info.value) sessions = server.get_sessions('/') assert 0 == len(sessions)
async def test__no_request_arguments_in_session_context(ManagedServerLoop): application = Application() with ManagedServerLoop(application) as server: response = await http_get(server.io_loop, url(server)) html = response.body sessionid = extract_sessionid_from_json(html) server_session = server.get_session('/', sessionid) server_doc = server_session.document session_context = server_doc.session_context # if we do not pass any arguments to the url, the request arguments # should be empty assert len(session_context.request.arguments) == 0
def test__lifecycle_hooks(ManagedServerLoop: MSL) -> None: application = Application() handler = HookTestHandler() application.add(handler) with ManagedServerLoop(application, check_unused_sessions_milliseconds=30) as server: client_session = pull_session(session_id=ID("test__lifecycle_hooks"), url=url(server), io_loop=server.io_loop) client_doc = client_session.document assert len(client_doc.roots) == 1 server_session = server.get_session('/', client_session.id) server_doc = server_session.document assert len(server_doc.roots) == 1 # save for later, since doc.roots will be emptied after the session is closed client_hook_list = list(client_doc.roots[0].hooks) server_hook_list = list(server_doc.roots[0].hooks) client_session.close() # expire the session quickly rather than after the usual timeout server_session.request_expiration() server.io_loop.call_later(0.1, lambda: server.io_loop.stop()) server.io_loop.start() assert handler.hooks == [ "server_loaded", "session_created", "modify", "next_tick", "timeout", "periodic", "session_destroyed", "server_unloaded", ] assert handler.load_count == 1 assert handler.unload_count == 1 # 3 instead of 6, because locked callbacks on destroyed sessions become no-ops assert handler.session_creation_async_value == 3 assert client_doc.title == "Modified" assert server_doc.title == "Modified" # only the handler sees "session_destroyed" since the session is shut down at that point. assert client_hook_list == ["session_created", "modify"] assert server_hook_list == ["session_created", "modify"]
async def test__reject_expired_session_websocket(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application, session_token_expiration=1) as server: sessions = server.get_sessions('/') assert 0 == len(sessions) response = await http_get(server.io_loop, url(server)) html = response.body token = extract_token_from_json(html) time.sleep(1.1) ws = await websocket_open(server.io_loop, ws_url(server), subprotocols=["bokeh", token]) assert await ws.read_queue.get() is None
async def test__accept_session_websocket(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application, session_token_expiration=1) as server: sessions = server.get_sessions('/') assert 0 == len(sessions) response = await http_get(server.io_loop, url(server)) html = response.body token = extract_token_from_json(html) ws = await websocket_open(server.io_loop, ws_url(server), subprotocols=["bokeh", token]) msg = await ws.read_queue.get() assert isinstance(msg, str) assert 'ACK' in msg
async def test__autocreate_signed_session_doc(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application, sign_sessions=True, secret_key='foo') as server: sessions = server.get_sessions('/') assert 0 == len(sessions) response = await http_get(server.io_loop, url(server)) html = response.body sessionid = extract_sessionid_from_json(html) sessions = server.get_sessions('/') assert 1 == len(sessions) assert sessionid == sessions[0].id assert check_session_id_signature(sessionid, signed=True, secret_key='foo')
async def test__reject_unsigned_session_doc(ManagedServerLoop): application = Application() with ManagedServerLoop(application, sign_sessions=True, secret_key='bar') as server: sessions = server.get_sessions('/') assert 0 == len(sessions) expected = 'foo' with (pytest.raises(HTTPError)) as info: await http_get(server.io_loop, url(server) + "?bokeh-session-id=" + expected) assert 'Invalid session ID' in repr(info.value) sessions = server.get_sessions('/') assert 0 == len(sessions)
async def test__reject_wrong_subprotocol_websocket(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application) as server: sessions = server.get_sessions('/') assert 0 == len(sessions) response = await http_get(server.io_loop, url(server)) html = response.body token = extract_token_from_json(html) sessions = server.get_sessions('/') assert 1 == len(sessions) ws = await websocket_open(server.io_loop, ws_url(server), subprotocols=["foo", token]) assert await ws.read_queue.get() is None
async def test__use_provided_session_doc(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application) as server: sessions = server.get_sessions('/') assert 0 == len(sessions) expected = 'foo' response = await http_get(server.io_loop, url(server) + "?bokeh-session-id=" + expected) html = response.body sessionid = extract_sessionid_from_json(html) assert expected == sessionid sessions = server.get_sessions('/') assert 1 == len(sessions) assert expected == sessions[0].id
async def test__actual_port_number(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application, port=0) as server: port = server.port assert port > 0 await http_get(server.io_loop, url(server))
def autoload_url(server): return url(server) + \ "autoload.js?bokeh-autoload-element=foo"
def test__lifecycle_hooks(ManagedServerLoop) -> None: application = Application() handler = HookTestHandler() application.add(handler) with ManagedServerLoop(application, check_unused_sessions_milliseconds=30) as server: # wait for server callbacks to run before we mix in the # session, this keeps the test deterministic def check_done(): if len(handler.hooks) == 4: server.io_loop.stop() server_load_checker = PeriodicCallback(check_done, 1) server_load_checker.start() server.io_loop.start() server_load_checker.stop() # now we create a session client_session = pull_session(session_id='test__lifecycle_hooks', url=url(server), io_loop=server.io_loop) client_doc = client_session.document assert len(client_doc.roots) == 1 server_session = server.get_session('/', client_session.id) server_doc = server_session.document assert len(server_doc.roots) == 1 # we have to capture these here for examination later, since after # the session is closed, doc.roots will be emptied client_hook_list = client_doc.roots[0] server_hook_list = server_doc.roots[0] client_session.close() # expire the session quickly rather than after the # usual timeout server_session.request_expiration() def on_done(): server.io_loop.stop() server.io_loop.call_later(0.1, on_done) server.io_loop.start() assert handler.hooks == ["server_loaded", "next_tick_server", "timeout_server", "periodic_server", "session_created", "modify", "next_tick_session", "timeout_session", "periodic_session", "session_destroyed", "server_unloaded"] assert handler.load_count == 1 assert handler.unload_count == 1 # this is 3 instead of 6 because locked callbacks on destroyed sessions # are turned into no-ops assert handler.session_creation_async_value == 3 assert client_doc.title == "Modified" assert server_doc.title == "Modified" # only the handler sees the event that adds "session_destroyed" since # the session is shut down at that point. assert client_hook_list.hooks == ["session_created", "modify"] assert server_hook_list.hooks == ["session_created", "modify"]