Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce prescription run to make sure each prescription reports once #2100

Merged
merged 1 commit into from
Sep 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions tests/prescription/v1/test_add_package_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -713,3 +713,97 @@ def test_run_package_version_already_resolved_same_name(self, context: Context,
assert "daiquiri" not in state.unresolved_dependencies
assert "daiquiri" in state.resolved_dependencies
assert set(state.resolved_dependencies["daiquiri"]) == set(pv_tuple)

def test_run_package_version_add_package_multi(self, context: Context, state: State) -> None:
"""Test running the unit multiple times with stack info and justification reported once."""
prescription_str = f"""
name: AddPackageStep
type: step.AddPackage
should_include:
adviser_pipeline: true
match:
package_version:
name: numpy
run:
package_version:
name: daiquiri
locked_version: ==2.0.0
index_url: https://pypi.org/simple
develop: true
stack_info:
- type: INFO
message: "Hello, Thoth!"
link: https://thoth-station.ninja
"""
prescription = yaml.safe_load(prescription_str)
PRESCRIPTION_ADD_PACKAGE_STEP_SCHEMA(prescription)
AddPackageStepPrescription.set_prescription(prescription)

pypi = Source("https://pypi.org/simple")
package_version_np = PackageVersion(
name="numpy",
version="==1.19.1",
index=pypi,
develop=False,
)

context.stack_info.clear()

context.graph.should_receive("python_package_version_exists").with_args(
"daiquiri", "2.0.0", "https://pypi.org/simple", solver_name="solver-rhel-8-py38"
).and_return(True).once()
context.graph.should_receive("is_python_package_index_enabled").with_args("https://pypi.org/simple").and_return(
True
).once()

state.resolved_dependencies.clear()

runtime_env = context.project.runtime_environment
runtime_env.operating_system.name = "rhel"
runtime_env.operating_system.version = "8"
runtime_env.python_version = "3.8"

unit = AddPackageStepPrescription()
unit.pre_run()
with unit.assigned_context(context):
assert unit.run(state, package_version_np) is None

assert "daiquiri" in state.unresolved_dependencies
assert set(state.unresolved_dependencies["daiquiri"].values()) == {
("daiquiri", "2.0.0", "https://pypi.org/simple")
}

assert context.stack_info == [
{"type": "INFO", "message": "Hello, Thoth!", "link": "https://thoth-station.ninja"}
]

package_version_np2 = PackageVersion(
name="numpy",
version="==2.0.0",
index=pypi,
develop=False,
)

context.graph.should_receive("python_package_version_exists").with_args(
"daiquiri", "2.0.0", "https://pypi.org/simple", solver_name="solver-rhel-8-py38"
).and_return(True).once()
context.graph.should_receive("is_python_package_index_enabled").with_args("https://pypi.org/simple").and_return(
True
).once()

state.resolved_dependencies.clear()

runtime_env = context.project.runtime_environment
runtime_env.operating_system.name = "rhel"
runtime_env.operating_system.version = "8"
runtime_env.python_version = "3.8"

with unit.assigned_context(context):
assert unit.run(state, package_version_np2) is None

assert set(state.unresolved_dependencies["daiquiri"].values()) == {
("daiquiri", "2.0.0", "https://pypi.org/simple")
}
assert context.stack_info == [
{"type": "INFO", "message": "Hello, Thoth!", "link": "https://thoth-station.ninja"}
]
49 changes: 47 additions & 2 deletions tests/prescription/v1/test_boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ def test_should_include_package_name(self) -> None:
"match": {
"package_name": "flask",
},
"prescription": {"run": False},
"run": {
"stack_info": [
{
Expand All @@ -174,7 +175,7 @@ def test_should_include_package_name(self) -> None:
}
]

def test_should_include_mutli(self) -> None:
def test_should_include_multi(self) -> None:
"""Test including this pipeline unit multiple times."""
prescription_str = """
name: BootUnit
Expand All @@ -197,12 +198,17 @@ def test_should_include_mutli(self) -> None:
BootPrescription.set_prescription(prescription)

builder_context = flexmock()
assert list(BootPrescription.should_include(builder_context)) == [
result = list(BootPrescription.should_include(builder_context))
assert len(result) == 2
assert result == [
{
"package_name": "flask",
"match": {
"package_name": "flask",
},
"prescription": {
"run": False,
},
"run": {
"stack_info": [
{
Expand All @@ -218,6 +224,9 @@ def test_should_include_mutli(self) -> None:
"match": {
"package_name": "pandas",
},
"prescription": {
"run": False,
},
"run": {
"stack_info": [
{
Expand All @@ -229,6 +238,7 @@ def test_should_include_mutli(self) -> None:
},
},
]
assert result[0]["prescription"] is result[1]["prescription"]

def test_should_include_no_package_name(self) -> None:
"""Test including this pipeline unit without package name."""
Expand All @@ -254,6 +264,7 @@ def test_should_include_no_package_name(self) -> None:
{
"match": {},
"package_name": None,
"prescription": {"run": False},
"run": {
"stack_info": [
{
Expand Down Expand Up @@ -287,3 +298,37 @@ def test_no_should_include(self) -> None:

builder_context = flexmock()
assert list(BootPrescription.should_include(builder_context)) == []

def test_should_include_multi_run(self, context: Context) -> None:
"""Test including this pipeline unit multiple times."""
prescription_str = """
name: BootUnit
type: boot
should_include:
times: 1
adviser_pipeline: true
match:
- package_name: flask
- package_name: pandas
run:
stack_info:
- type: INFO
message: "Hello, Thoth!"
link: https://thoth-station.ninja
"""
prescription = yaml.safe_load(prescription_str)
PRESCRIPTION_BOOT_SCHEMA(prescription)
BootPrescription.set_prescription(prescription)
unit = BootPrescription()

assert "flask" in (pv.name for pv in context.project.iter_dependencies())

unit.pre_run()
with unit.assigned_context(context):
# Run twice.
unit.run()
unit.run()

assert context.stack_info == [
{"type": "INFO", "message": "Hello, Thoth!", "link": "https://thoth-station.ninja"}
]
6 changes: 6 additions & 0 deletions tests/prescription/v1/test_gh_release_notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ def test_run_develop(self, context: Context, state: State, develop: bool) -> Non

unit.pre_run()
with unit.assigned_context(context):
# Run twice to verify the justification is added just once.
assert unit.run(state) is None
assert unit.run(state) is None

self.verify_justification_schema(state.justification)
Expand Down Expand Up @@ -326,13 +328,17 @@ def test_instantiate_multiple(self) -> None:
"""
units = list(self._instantiate_gh_release_notes_wrap(prescription_str))
assert len(units) == 2
assert units[0].configuration["prescription"] is units[1].configuration["prescription"]

assert units[0].configuration == {
"package_name": "requests-fork",
"package_version": {"index_url": "https://pypi.org/simple", "name": "requests-fork"},
"release_notes": {"organization": "psf", "repository": "requests"},
"prescription": {"run": False},
}
assert units[1].configuration == {
"package_name": "requests",
"package_version": {"name": "requests"},
"release_notes": {"organization": "psf", "repository": "requests"},
"prescription": {"run": False},
}
76 changes: 75 additions & 1 deletion tests/prescription/v1/test_pseudonym.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,67 @@ def test_run_stack_info(self, context: Context) -> None:
).and_return([("flask", "1.2.0", "https://pypi.org/simple")]).once()
self.check_run_stack_info(context, PseudonymPrescription, package_version=package_version)

def test_run_stack_info_multi_call(self, context: Context) -> None:
"""Make sure the stack info is added just once on multiple calls."""
prescription_str = """
name: PseudonymUnit
type: pseudonym
should_include:
times: 1
adviser_pipeline: true
match:
package_version:
name: flask
version: '>1.0,<=1.1.0'
index_url: 'https://pypi.org/simple'
run:
yield:
package_version:
name: flask
locked_version: ==1.2.0
index_url: 'https://pypi.org/simple'

stack_info:
- type: WARNING
message: Some stack warning message
link: https://thoth-station.ninja
"""
prescription = yaml.safe_load(prescription_str)
PRESCRIPTION_PSEUDONYM_SCHEMA(prescription)
PseudonymPrescription.set_prescription(prescription)
package_version = PackageVersion(
name="flask",
version="==1.1.0",
index=Source("https://pypi.org/simple"),
develop=False,
)

context.graph.should_receive("get_solved_python_package_versions_all").with_args(
package_name="flask",
package_version="1.2.0",
index_url="https://pypi.org/simple",
count=None,
os_name=context.project.runtime_environment.operating_system.name,
os_version=context.project.runtime_environment.operating_system.version,
python_version=context.project.runtime_environment.python_version,
distinct=True,
is_missing=False,
).and_return([("flask", "1.2.0", "https://pypi.org/simple")]).twice()

assert not context.stack_info

unit = PseudonymPrescription()
unit.pre_run()
with unit.assigned_context(context):
result = list(unit.run(package_version))
assert result == [("flask", "1.2.0", "https://pypi.org/simple")]
result = list(unit.run(package_version))
assert result == [("flask", "1.2.0", "https://pypi.org/simple")]

assert self.verify_justification_schema(context.stack_info)
assert len(context.stack_info) == 1, "Only one stack info should be included"
assert context.stack_info == unit.run_prescription["stack_info"]

@pytest.mark.parametrize("log_level", ["INFO", "ERROR", "WARNING"])
def test_run_log(self, caplog, context: Context, log_level: str) -> None:
"""Check logging messages."""
Expand Down Expand Up @@ -221,6 +282,7 @@ def test_should_include_package_name(self) -> None:
"index_url": "https://pypi.org/simple",
},
},
"prescription": {"run": False},
"run": {
"yield": {
"package_version": {
Expand Down Expand Up @@ -263,14 +325,23 @@ def test_should_include_multi(self) -> None:
PseudonymPrescription.set_prescription(prescription)

builder_context = flexmock()
assert list(PseudonymPrescription.should_include(builder_context)) == [
result = list(PseudonymPrescription.should_include(builder_context))
assert len(result) == 4

prescription_conf = result[0]["prescription"]
assert prescription_conf == {"run": False}
for item in result:
assert item["prescription"] is prescription_conf

assert result == [
{
"package_name": "tensorflow-cpu",
"match": {
"package_version": {
"name": "tensorflow-cpu",
}
},
"prescription": {"run": False},
"run": {
"yield": {
"package_version": {
Expand All @@ -288,6 +359,7 @@ def test_should_include_multi(self) -> None:
"name": "tensorflow-gpu",
}
},
"prescription": {"run": False},
"run": {
"yield": {
"package_version": {
Expand All @@ -305,6 +377,7 @@ def test_should_include_multi(self) -> None:
"name": "intel-tensorflow",
}
},
"prescription": {"run": False},
"run": {
"yield": {
"package_version": {
Expand All @@ -322,6 +395,7 @@ def test_should_include_multi(self) -> None:
"name": "tensorflow",
}
},
"prescription": {"run": False},
"run": {
"yield": {
"package_version": {
Expand Down
Loading