Skip to content

Commit e59cfe1

Browse files
authored
Merge branch 'main' into mlflow
2 parents 561d695 + 7cf42f9 commit e59cfe1

12 files changed

+209
-132
lines changed

conftest.py

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,73 @@
1-
import os
21
from pathlib import Path
32

43
import pytest
4+
from sqlalchemy import create_engine
5+
from sqlalchemy.orm import Session, sessionmaker
56

6-
from jupyter_scheduler.orm import create_session, create_tables
7+
from jupyter_scheduler.orm import Base
78
from jupyter_scheduler.scheduler import Scheduler
89
from jupyter_scheduler.tests.mocks import MockEnvironmentManager
910

10-
pytest_plugins = ("jupyter_server.pytest_plugin",)
11+
pytest_plugins = ("jupyter_server.pytest_plugin", "pytest_jupyter.jupyter_server")
1112

12-
HERE = Path(__file__).parent.resolve()
13-
DB_FILE_PATH = f"{HERE}/jupyter_scheduler/tests/testdb.sqlite"
14-
DB_URL = f"sqlite:///{DB_FILE_PATH}"
1513

16-
TEST_ROOT_DIR = f"{HERE}/jupyter_scheduler/tests/test_root_dir"
14+
@pytest.fixture(scope="session")
15+
def static_test_files_dir() -> Path:
16+
return Path(__file__).parent.resolve() / "jupyter_scheduler" / "tests" / "static"
1717

1818

1919
@pytest.fixture
20-
def jp_server_config(jp_server_config):
20+
def jp_scheduler_root_dir(tmp_path: Path) -> Path:
21+
root_dir = tmp_path / "workspace_root"
22+
root_dir.mkdir()
23+
return root_dir
24+
25+
26+
@pytest.fixture
27+
def jp_scheduler_output_dir(jp_scheduler_root_dir: Path) -> Path:
28+
output_dir = jp_scheduler_root_dir / "jobs"
29+
output_dir.mkdir()
30+
return output_dir
31+
32+
33+
@pytest.fixture
34+
def jp_scheduler_staging_dir(jp_data_dir: Path) -> Path:
35+
staging_area = jp_data_dir / "scheduler_staging_area"
36+
staging_area.mkdir()
37+
return staging_area
38+
39+
40+
@pytest.fixture
41+
def jp_scheduler_db_url(jp_scheduler_staging_dir: Path) -> str:
42+
db_file_path = jp_scheduler_staging_dir / "scheduler.sqlite"
43+
return f"sqlite:///{db_file_path}"
44+
45+
46+
@pytest.fixture
47+
def jp_scheduler_db(jp_scheduler_db_url):
48+
engine = create_engine(jp_scheduler_db_url, echo=False)
49+
Base.metadata.create_all(engine)
50+
Session = sessionmaker(bind=engine)
51+
session = Session()
52+
yield session
53+
session.close()
54+
55+
56+
@pytest.fixture
57+
def jp_scheduler(jp_scheduler_db_url, jp_scheduler_root_dir, jp_scheduler_db):
58+
return Scheduler(
59+
db_url=jp_scheduler_db_url,
60+
root_dir=str(jp_scheduler_root_dir),
61+
environments_manager=MockEnvironmentManager(),
62+
)
63+
64+
65+
@pytest.fixture
66+
def jp_server_config(jp_scheduler_db_url, jp_server_config):
2167
return {
2268
"ServerApp": {"jpserver_extensions": {"jupyter_scheduler": True}},
2369
"SchedulerApp": {
24-
"db_url": DB_URL,
70+
"db_url": jp_scheduler_db_url,
2571
"drop_tables": True,
2672
"environment_manager_class": "jupyter_scheduler.tests.mocks.MockEnvironmentManager",
2773
},
@@ -30,23 +76,3 @@ def jp_server_config(jp_server_config):
3076
},
3177
"Scheduler": {"task_runner_class": "jupyter_scheduler.tests.mocks.MockTaskRunner"},
3278
}
33-
34-
35-
@pytest.fixture(autouse=True)
36-
def setup_db():
37-
create_tables(DB_URL, True)
38-
yield
39-
if os.path.exists(DB_FILE_PATH):
40-
os.remove(DB_FILE_PATH)
41-
42-
43-
@pytest.fixture
44-
def jp_scheduler_db():
45-
return create_session(DB_URL)
46-
47-
48-
@pytest.fixture
49-
def jp_scheduler():
50-
return Scheduler(
51-
db_url=DB_URL, root_dir=str(TEST_ROOT_DIR), environments_manager=MockEnvironmentManager()
52-
)
Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,60 @@
1+
import shutil
12
from pathlib import Path
3+
from typing import Tuple
24

35
import pytest
4-
from sqlalchemy import create_engine
5-
from sqlalchemy.orm import sessionmaker
66

7-
from conftest import DB_URL
87
from jupyter_scheduler.executors import DefaultExecutionManager
98
from jupyter_scheduler.orm import Job
109

11-
JOB_ID = "69856f4e-ce94-45fd-8f60-3a587457fce7"
12-
NOTEBOOK_NAME = "side_effects.ipynb"
13-
SIDE_EFECT_FILE_NAME = "output_side_effect.txt"
1410

15-
NOTEBOOK_DIR = Path(__file__).resolve().parent / "test_staging_dir" / "job-4"
16-
NOTEBOOK_PATH = NOTEBOOK_DIR / NOTEBOOK_NAME
17-
SIDE_EFFECT_FILE = NOTEBOOK_DIR / SIDE_EFECT_FILE_NAME
11+
@pytest.fixture
12+
def staging_dir_with_side_effects(
13+
static_test_files_dir, jp_scheduler_staging_dir
14+
) -> Tuple[Path, Path]:
15+
notebook_file_path = static_test_files_dir / "side_effects.ipynb"
16+
side_effect_file_path = static_test_files_dir / "output_side_effect.txt"
17+
job_staging_dir = jp_scheduler_staging_dir / "job-4"
18+
19+
job_staging_dir.mkdir()
20+
shutil.copy2(notebook_file_path, job_staging_dir)
21+
shutil.copy2(side_effect_file_path, job_staging_dir)
22+
23+
return (notebook_file_path, side_effect_file_path)
1824

1925

2026
@pytest.fixture
21-
def load_job(jp_scheduler_db):
22-
with jp_scheduler_db() as session:
23-
job = Job(
24-
runtime_environment_name="abc",
25-
input_filename=NOTEBOOK_NAME,
26-
job_id=JOB_ID,
27-
)
28-
session.add(job)
29-
session.commit()
30-
31-
32-
def test_add_side_effects_files(jp_scheduler_db, load_job):
27+
def side_effects_job_record(staging_dir_with_side_effects, jp_scheduler_db) -> str:
28+
notebook_name = staging_dir_with_side_effects[0].name
29+
job = Job(
30+
runtime_environment_name="abc",
31+
input_filename=notebook_name,
32+
)
33+
jp_scheduler_db.add(job)
34+
jp_scheduler_db.commit()
35+
36+
return job.job_id
37+
38+
39+
def test_add_side_effects_files(
40+
side_effects_job_record,
41+
staging_dir_with_side_effects,
42+
jp_scheduler_root_dir,
43+
jp_scheduler_db_url,
44+
jp_scheduler_db,
45+
):
46+
job_id = side_effects_job_record
47+
staged_notebook_file_path = staging_dir_with_side_effects[0]
48+
staged_notebook_dir = staged_notebook_file_path.parent
49+
side_effect_file_name = staging_dir_with_side_effects[1].name
50+
3351
manager = DefaultExecutionManager(
34-
job_id=JOB_ID,
35-
root_dir=str(NOTEBOOK_DIR),
36-
db_url=DB_URL,
37-
staging_paths={"input": str(NOTEBOOK_PATH)},
52+
job_id=job_id,
53+
root_dir=jp_scheduler_root_dir,
54+
db_url=jp_scheduler_db_url,
55+
staging_paths={"input": staged_notebook_file_path},
3856
)
39-
manager.add_side_effects_files(str(NOTEBOOK_DIR))
57+
manager.add_side_effects_files(staged_notebook_dir)
4058

41-
with jp_scheduler_db() as session:
42-
job = session.query(Job).filter(Job.job_id == JOB_ID).one()
43-
assert SIDE_EFECT_FILE_NAME in job.packaged_files
59+
job = jp_scheduler_db.query(Job).filter(Job.job_id == job_id).one()
60+
assert side_effect_file_name in job.packaged_files

jupyter_scheduler/tests/test_job_files_manager.py

Lines changed: 65 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -60,65 +60,88 @@ async def test_copy_from_staging():
6060
)
6161

6262

63-
HERE = Path(__file__).parent.resolve()
64-
OUTPUTS_DIR = os.path.join(HERE, "test_files_output")
63+
@pytest.fixture
64+
def staging_dir_with_notebook_job(static_test_files_dir, jp_scheduler_staging_dir):
65+
staging_dir = jp_scheduler_staging_dir / "job-1"
66+
job_filenames = ["helloworld-1.ipynb", "helloworld-1.html", "helloworld.ipynb"]
67+
68+
staged_job_files = []
69+
staging_dir.mkdir()
70+
for job_filename in job_filenames:
71+
staged_job_file = shutil.copy2(static_test_files_dir / job_filename, staging_dir)
72+
staged_job_files.append(staged_job_file)
73+
74+
return staged_job_files
6575

6676

6777
@pytest.fixture
68-
def clear_outputs_dir():
69-
yield
70-
shutil.rmtree(OUTPUTS_DIR)
71-
# rmtree() is not synchronous; wait until it has finished running
72-
while os.path.isdir(OUTPUTS_DIR):
73-
time.sleep(0.01)
74-
75-
76-
@pytest.mark.parametrize(
77-
"output_formats, output_filenames, staging_paths, output_dir, redownload",
78-
[
79-
(
80-
["ipynb", "html"],
81-
{
78+
def staging_dir_with_tar_job(static_test_files_dir, jp_scheduler_staging_dir):
79+
staging_dir = jp_scheduler_staging_dir / "job-2"
80+
job_tar_file = static_test_files_dir / "helloworld.tar.gz"
81+
82+
staging_dir.mkdir()
83+
staged_tar_file = shutil.copy2(job_tar_file, staging_dir)
84+
85+
return staged_tar_file
86+
87+
88+
@pytest.fixture
89+
def downloader_parameters(
90+
staging_dir_with_notebook_job,
91+
staging_dir_with_tar_job,
92+
request,
93+
jp_scheduler_output_dir,
94+
):
95+
job_1_ipynb_file_path, job_1_html_file_path, job_1_input_file_path = (
96+
staging_dir_with_notebook_job
97+
)
98+
job_2_tar_file_path = staging_dir_with_tar_job
99+
index = request.param
100+
parameters = [
101+
{
102+
"output_formats": ["ipynb", "html"],
103+
"output_filenames": {
82104
"ipynb": "job-1/helloworld-out.ipynb",
83105
"html": "job-1/helloworld-out.html",
84106
"input": "job-1/helloworld-input.ipynb",
85107
},
86-
{
87-
"ipynb": os.path.join(HERE, "test_staging_dir", "job-1", "helloworld-1.ipynb"),
88-
"html": os.path.join(HERE, "test_staging_dir", "job-1", "helloworld-1.html"),
89-
"input": os.path.join(HERE, "test_staging_dir", "job-1", "helloworld.ipynb"),
108+
"staging_paths": {
109+
"ipynb": job_1_ipynb_file_path,
110+
"html": job_1_html_file_path,
111+
"input": job_1_input_file_path,
90112
},
91-
OUTPUTS_DIR,
92-
False,
93-
),
94-
(
95-
["ipynb", "html"],
96-
{
113+
"output_dir": jp_scheduler_output_dir,
114+
"redownload": False,
115+
},
116+
{
117+
"output_formats": ["ipynb", "html"],
118+
"output_filenames": {
97119
"ipynb": "job-2/helloworld-1.ipynb",
98120
"html": "job-2/helloworld-1.html",
99121
"input": "job-2/helloworld.ipynb",
100122
},
101-
{
102-
"tar.gz": os.path.join(HERE, "test_staging_dir", "job-2", "helloworld.tar.gz"),
123+
"staging_paths": {
124+
"tar.gz": job_2_tar_file_path,
103125
"ipynb": "job-2/helloworld-1.ipynb",
104126
"html": "job-2/helloworld-1.html",
105127
"input": "job-2/helloworld.ipynb",
106128
},
107-
OUTPUTS_DIR,
108-
False,
109-
),
110-
],
111-
)
112-
def test_downloader_download(
113-
clear_outputs_dir, output_formats, output_filenames, staging_paths, output_dir, redownload
114-
):
115-
downloader = Downloader(
116-
output_formats=output_formats,
117-
output_filenames=output_filenames,
118-
staging_paths=staging_paths,
119-
output_dir=output_dir,
120-
redownload=redownload,
129+
"output_dir": jp_scheduler_output_dir,
130+
"redownload": False,
131+
},
132+
]
133+
return parameters[index]
134+
135+
136+
@pytest.mark.parametrize("downloader_parameters", [0, 1], indirect=True)
137+
def test_downloader_download(downloader_parameters):
138+
output_formats, output_filenames, staging_paths, output_dir = (
139+
downloader_parameters["output_formats"],
140+
downloader_parameters["output_filenames"],
141+
downloader_parameters["staging_paths"],
142+
downloader_parameters["output_dir"],
121143
)
144+
downloader = Downloader(**downloader_parameters)
122145
downloader.download()
123146

124147
assert os.path.exists(output_dir)

0 commit comments

Comments
 (0)