From 2eed619745a583c33dfed681d3845c545d3b17ee Mon Sep 17 00:00:00 2001 From: Jean-Marc Alkazzi Date: Mon, 26 Oct 2020 21:22:11 +0100 Subject: [PATCH] Add integration test for user code execution with custom base_url --- integration-tests/test_hub.py | 199 ++++++++++++++++++++-------------- 1 file changed, 116 insertions(+), 83 deletions(-) diff --git a/integration-tests/test_hub.py b/integration-tests/test_hub.py index 22dfbbf..b57837e 100644 --- a/integration-tests/test_hub.py +++ b/integration-tests/test_hub.py @@ -18,6 +18,7 @@ from tljh.normalize import generate_system_username # This catches issues with PATH TLJH_CONFIG_PATH = ['sudo', 'tljh-config'] + def test_hub_up(): r = requests.get('http://127.0.0.1') r.raise_for_status() @@ -37,13 +38,41 @@ async def test_user_code_execute(): assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait() async with User(username, hub_url, partial(login_dummy, password='')) as u: - await u.login() - await u.ensure_server_simulate() - await u.start_kernel() - await u.assert_code_output("5 * 4", "20", 5, 5) + await u.login() + await u.ensure_server_simulate() + await u.start_kernel() + await u.assert_code_output("5 * 4", "20", 5, 5) - # Assert that the user exists - assert pwd.getpwnam(f'jupyter-{username}') is not None + # Assert that the user exists + assert pwd.getpwnam(f'jupyter-{username}') is not None + + +@pytest.mark.asyncio +async def test_user_code_execute_with_custom_base_url(): + """ + User logs in, starts a server with a custom base_url & executes code + """ + # This *must* be localhost, not an IP + # aiohttp throws away cookies if we are connecting to an IP! + hub_url = 'http://localhost' + username = secrets.token_hex(8) + + assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'set', 'auth.type', 'dummyauthenticator.DummyAuthenticator')).wait() + assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'set', 'base_url', '/custom-base')).wait() + assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait() + + async with User(username, hub_url, partial(login_dummy, password='')) as u: + await u.login() + await u.ensure_server_simulate() + await u.start_kernel() + await u.assert_code_output("5 * 4", "20", 5, 5) + + # Assert that the user exists + assert pwd.getpwnam(f'jupyter-{username}') is not None + + # unset base_url to avoid problems with other tests + assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'unset', 'base_url')).wait() + assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait() @pytest.mark.asyncio @@ -61,14 +90,15 @@ async def test_user_admin_add(): assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait() async with User(username, hub_url, partial(login_dummy, password='')) as u: - await u.login() - await u.ensure_server_simulate() + await u.login() + await u.ensure_server_simulate() - # Assert that the user exists - assert pwd.getpwnam(f'jupyter-{username}') is not None + # Assert that the user exists + assert pwd.getpwnam(f'jupyter-{username}') is not None - # Assert that the user has admin rights - assert f'jupyter-{username}' in grp.getgrnam('jupyterhub-admins').gr_mem + # Assert that the user has admin rights + assert f'jupyter-{username}' in grp.getgrnam( + 'jupyterhub-admins').gr_mem # FIXME: Make this test pass @@ -90,23 +120,25 @@ async def test_user_admin_remove(): assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait() async with User(username, hub_url, partial(login_dummy, password='')) as u: - await u.login() - await u.ensure_server_simulate() + await u.login() + await u.ensure_server_simulate() - # Assert that the user exists - assert pwd.getpwnam(f'jupyter-{username}') is not None + # Assert that the user exists + assert pwd.getpwnam(f'jupyter-{username}') is not None - # Assert that the user has admin rights - assert f'jupyter-{username}' in grp.getgrnam('jupyterhub-admins').gr_mem + # Assert that the user has admin rights + assert f'jupyter-{username}' in grp.getgrnam( + 'jupyterhub-admins').gr_mem - assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'remove-item', 'users.admin', username)).wait() - assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait() + assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'remove-item', 'users.admin', username)).wait() + assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait() - await u.stop_server() - await u.ensure_server_simulate() + await u.stop_server() + await u.ensure_server_simulate() - # Assert that the user does *not* have admin rights - assert f'jupyter-{username}' not in grp.getgrnam('jupyterhub-admins').gr_mem + # Assert that the user does *not* have admin rights + assert f'jupyter-{username}' not in grp.getgrnam( + 'jupyterhub-admins').gr_mem @pytest.mark.asyncio @@ -124,14 +156,14 @@ async def test_long_username(): try: async with User(username, hub_url, partial(login_dummy, password='')) as u: - await u.login() - await u.ensure_server_simulate() + await u.login() + await u.ensure_server_simulate() - # Assert that the user exists - system_username = generate_system_username(f'jupyter-{username}') - assert pwd.getpwnam(system_username) is not None + # Assert that the user exists + system_username = generate_system_username(f'jupyter-{username}') + assert pwd.getpwnam(system_username) is not None - await u.stop_server() + await u.stop_server() except: # If we have any errors, print jupyterhub logs before exiting subprocess.check_call([ @@ -161,19 +193,19 @@ async def test_user_group_adding(): try: async with User(username, hub_url, partial(login_dummy, password='')) as u: - await u.login() - await u.ensure_server_simulate() + await u.login() + await u.ensure_server_simulate() - # Assert that the user exists - system_username = generate_system_username(f'jupyter-{username}') - assert pwd.getpwnam(system_username) is not None + # Assert that the user exists + system_username = generate_system_username(f'jupyter-{username}') + assert pwd.getpwnam(system_username) is not None - # Assert that the user was added to the specified group - assert f'jupyter-{username}' in grp.getgrnam('somegroup').gr_mem + # Assert that the user was added to the specified group + assert f'jupyter-{username}' in grp.getgrnam('somegroup').gr_mem - await u.stop_server() - # Delete the group - system('groupdel somegroup') + await u.stop_server() + # Delete the group + system('groupdel somegroup') except: # If we have any errors, print jupyterhub logs before exiting subprocess.check_call([ @@ -205,29 +237,30 @@ async def test_idle_server_culled(): assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait() async with User(username, hub_url, partial(login_dummy, password='')) as u: - await u.login() - # Start user's server - await u.ensure_server_simulate() - # Assert that the user exists - assert pwd.getpwnam(f'jupyter-{username}') is not None + await u.login() + # Start user's server + await u.ensure_server_simulate() + # Assert that the user exists + assert pwd.getpwnam(f'jupyter-{username}') is not None - # Check that we can get to the user's server + # Check that we can get to the user's server + r = await u.session.get(u.hub_url / 'hub/api/users' / username, + headers={'Referer': str(u.hub_url / 'hub/')}) + assert r.status == 200 + + async def _check_culling_done(): + # Check that after 60s, the user and server have been culled and are not reacheable anymore r = await u.session.get(u.hub_url / 'hub/api/users' / username, - headers={'Referer': str(u.hub_url / 'hub/')}) - assert r.status == 200 + headers={'Referer': str(u.hub_url / 'hub/')}) + print(r.status) + return r.status == 403 - async def _check_culling_done(): - # Check that after 60s, the user and server have been culled and are not reacheable anymore - r = await u.session.get(u.hub_url / 'hub/api/users' / username, - headers={'Referer': str(u.hub_url / 'hub/')}) - print(r.status) - return r.status == 403 + await exponential_backoff( + _check_culling_done, + "Server culling failed!", + timeout=100, + ) - await exponential_backoff( - _check_culling_done, - "Server culling failed!", - timeout=100, - ) @pytest.mark.asyncio async def test_active_server_not_culled(): @@ -250,30 +283,30 @@ async def test_active_server_not_culled(): assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait() async with User(username, hub_url, partial(login_dummy, password='')) as u: - await u.login() - # Start user's server - await u.ensure_server_simulate() - # Assert that the user exists - assert pwd.getpwnam(f'jupyter-{username}') is not None + await u.login() + # Start user's server + await u.ensure_server_simulate() + # Assert that the user exists + assert pwd.getpwnam(f'jupyter-{username}') is not None - # Check that we can get to the user's server + # Check that we can get to the user's server + r = await u.session.get(u.hub_url / 'hub/api/users' / username, + headers={'Referer': str(u.hub_url / 'hub/')}) + assert r.status == 200 + + async def _check_culling_done(): + # Check that after 30s, we can still reach the user's server r = await u.session.get(u.hub_url / 'hub/api/users' / username, - headers={'Referer': str(u.hub_url / 'hub/')}) - assert r.status == 200 + headers={'Referer': str(u.hub_url / 'hub/')}) + print(r.status) + return r.status != 200 - async def _check_culling_done(): - # Check that after 30s, we can still reach the user's server - r = await u.session.get(u.hub_url / 'hub/api/users' / username, - headers={'Referer': str(u.hub_url / 'hub/')}) - print(r.status) - return r.status != 200 - - try: - await exponential_backoff( - _check_culling_done, - "User's server is still reacheable!", - timeout=30, - ) - except TimeoutError: - # During the 30s timeout the user's server wasn't culled, which is what we intended. - pass + try: + await exponential_backoff( + _check_culling_done, + "User's server is still reacheable!", + timeout=30, + ) + except TimeoutError: + # During the 30s timeout the user's server wasn't culled, which is what we intended. + pass