2024-02-14 10:48:56 +01:00
|
|
|
"""Test GLiCID spawner module."""
|
|
|
|
|
|
|
|
from collections import namedtuple
|
2024-02-22 17:41:58 +01:00
|
|
|
from itertools import repeat
|
2024-02-14 10:48:56 +01:00
|
|
|
|
|
|
|
import glicid_spawner.spawner
|
2024-02-22 17:41:58 +01:00
|
|
|
import pytest
|
2024-03-08 17:16:30 +01:00
|
|
|
from batchspawner import SlurmSpawner, format_template
|
2024-02-14 10:48:56 +01:00
|
|
|
from glicid_spawner import GlicidSpawner
|
2024-02-22 17:41:58 +01:00
|
|
|
from glicid_spawner.spawner import asyncio
|
2024-02-14 10:48:56 +01:00
|
|
|
|
2024-03-08 17:16:30 +01:00
|
|
|
User = namedtuple('User', 'name,url')
|
|
|
|
Hub = namedtuple('Hub', 'public_host,api_url,base_url')
|
2024-02-14 10:48:56 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_spawner_config():
|
|
|
|
"""Test spawner configuration."""
|
2024-02-22 17:41:58 +01:00
|
|
|
spawner = GlicidSpawner(progress_rate=10)
|
2024-02-14 10:48:56 +01:00
|
|
|
|
|
|
|
assert isinstance(spawner, GlicidSpawner)
|
|
|
|
assert isinstance(spawner, SlurmSpawner)
|
|
|
|
|
|
|
|
assert spawner.batchspawner_singleuser_cmd == 'glicid-spawner-singleuser'
|
|
|
|
|
2024-03-08 18:00:46 +01:00
|
|
|
assert spawner.req_mamba_root_prefix == '/micromamba/operator'
|
|
|
|
assert spawner.req_mamba_exe == '/micromamba/operator/bin/micromamba'
|
|
|
|
assert spawner.req_job_name == 'jupyterhub_glicid'
|
|
|
|
assert spawner.req_qos == 'short'
|
|
|
|
|
2024-02-26 14:54:56 +01:00
|
|
|
assert spawner.disable_user_config
|
|
|
|
assert spawner.notebook_dir == '/'
|
2024-03-08 10:42:39 +01:00
|
|
|
assert spawner.default_url == '/lab/tree/home/{username}?reset'
|
2024-02-22 17:41:58 +01:00
|
|
|
assert spawner.progress_rate == 10
|
2024-02-21 15:11:14 +01:00
|
|
|
|
|
|
|
|
2024-03-08 17:16:30 +01:00
|
|
|
def test_spawner_batch_script(monkeypatch):
|
|
|
|
"""Test spawner SLURM batch script."""
|
|
|
|
monkeypatch.setattr(GlicidSpawner, 'get_env', lambda _: {})
|
|
|
|
|
|
|
|
spawner = GlicidSpawner(
|
|
|
|
user=User('john-doe', '/john-doe/'),
|
|
|
|
req_homedir='/home/john-doe',
|
|
|
|
hub=Hub('public.hostname', 'api.url', 'base.url'),
|
|
|
|
user_options={
|
|
|
|
'cluster': 'nautilus',
|
|
|
|
'workdir': '/home/john-doe',
|
|
|
|
'pyenv': '/micromamba/john-doe/envs/foo',
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
script = format_template(
|
|
|
|
spawner.batch_script, **(spawner.get_req_subvars() | spawner.user_options)
|
|
|
|
)
|
|
|
|
|
|
|
|
assert '#SBATCH --job-name=jupyterhub_glicid' in script
|
|
|
|
assert '#SBATCH --chdir=/home/john-doe' in script
|
|
|
|
assert '#SBATCH --cluster=nautilus' in script
|
|
|
|
assert '#SBATCH --qos=short' in script
|
|
|
|
|
|
|
|
assert 'export JUPYTER_LOG_DIR="/home/john-doe/.jupyter/spawner/logs"' in script
|
|
|
|
|
2024-03-08 18:00:46 +01:00
|
|
|
assert 'export MAMBA_EXE=/micromamba/operator/bin/micromamba;' in script
|
|
|
|
assert 'export MAMBA_ROOT_PREFIX=/micromamba/operator;' in script
|
2024-03-08 17:16:30 +01:00
|
|
|
assert 'micromamba activate /micromamba/john-doe/envs/foo;' in script
|
|
|
|
|
|
|
|
|
2024-02-21 15:11:14 +01:00
|
|
|
def test_spawner_parse_job_id():
|
|
|
|
"""Test spawner job id parser."""
|
|
|
|
spawner = GlicidSpawner()
|
|
|
|
|
|
|
|
assert spawner.parse_job_id('123') == 123
|
|
|
|
assert spawner.parse_job_id('456;nautilus') == '456 -M nautilus'
|
|
|
|
|
|
|
|
assert spawner.parse_job_id('') is None
|
|
|
|
|
2024-02-14 10:48:56 +01:00
|
|
|
|
|
|
|
def test_spawner_options_form(monkeypatch):
|
|
|
|
"""Test spawner options form."""
|
|
|
|
monkeypatch.setattr(
|
|
|
|
glicid_spawner.spawner, 'options_form', lambda username: f"options_form('{username}')"
|
|
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
|
|
glicid_spawner.spawner,
|
|
|
|
'options_from_form',
|
|
|
|
lambda formdata: f'options_from_form({formdata})',
|
|
|
|
)
|
|
|
|
|
2024-03-08 17:16:30 +01:00
|
|
|
spawner = GlicidSpawner(user=User('john-doe', '/john-doe/'))
|
2024-02-14 10:48:56 +01:00
|
|
|
|
|
|
|
assert spawner.user.name == 'john-doe'
|
2024-02-21 15:11:14 +01:00
|
|
|
assert spawner.options_form == "options_form('john-doe')"
|
2024-02-14 10:48:56 +01:00
|
|
|
assert spawner.options_from_form({'foo': 123}) == "options_from_form({'foo': 123})"
|
2024-02-22 17:41:58 +01:00
|
|
|
|
2024-02-26 14:54:56 +01:00
|
|
|
spawner = GlicidSpawner(user_options={'workdir': '/LAB-DATA'})
|
|
|
|
|
2024-03-08 10:42:39 +01:00
|
|
|
assert spawner.default_url == '/lab/tree/LAB-DATA?reset'
|
2024-02-26 14:54:56 +01:00
|
|
|
|
2024-02-22 17:41:58 +01:00
|
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
|
|
async def test_spawner_progress(monkeypatch):
|
|
|
|
"""Test spawner progress messages."""
|
|
|
|
|
|
|
|
def isrunning():
|
|
|
|
"""Running generator values."""
|
|
|
|
yield False # NOTFOUND
|
|
|
|
yield False # PENDING
|
|
|
|
yield from repeat(True) # RUNNING
|
|
|
|
|
|
|
|
def ispending():
|
|
|
|
"""Pending generator values."""
|
|
|
|
yield False # NOTFOUND
|
|
|
|
yield True # PENDING
|
|
|
|
yield from repeat(False) # RUNNING (never used)
|
|
|
|
|
|
|
|
# Mock Job status generator
|
|
|
|
iter_ispending = iter(ispending())
|
|
|
|
iter_isrunning = iter(isrunning())
|
|
|
|
|
|
|
|
monkeypatch.setattr(
|
|
|
|
glicid_spawner.GlicidSpawner, 'state_isrunning', lambda _: next(iter_isrunning)
|
|
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
|
|
glicid_spawner.GlicidSpawner, 'state_ispending', lambda _: next(iter_ispending)
|
|
|
|
)
|
|
|
|
|
|
|
|
async def mock_sleep(_):
|
|
|
|
"""Mock asyncio sleep."""
|
|
|
|
|
|
|
|
monkeypatch.setattr(asyncio, 'sleep', mock_sleep)
|
|
|
|
|
|
|
|
spawner = GlicidSpawner(progress_rate=20)
|
|
|
|
|
|
|
|
progress = [msg['progress'] async for msg in spawner.progress()]
|
|
|
|
|
|
|
|
assert progress == [
|
|
|
|
10, # submit
|
|
|
|
20, # pending
|
|
|
|
60, # running | elapse time = 20 -> setup
|
|
|
|
80, # running | elapse time = 40 -> connect
|
|
|
|
95, # running | elapse time = 60 -> too long
|
|
|
|
]
|