Skip to content

Commit 9bfdf2e

Browse files
authored
[ML][Pipelines]test: shorten test name to enable recording (Azure#26995)
* feat: shorten test name to enable recording * fix: fix ci
1 parent 1063e29 commit 9bfdf2e

File tree

39 files changed

+28995
-966
lines changed

39 files changed

+28995
-966
lines changed

sdk/ml/azure-ai-ml/tests/internal/_utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from pathlib import Path
2+
13
import pydash
24

35
from azure.ai.ml import Input
@@ -178,6 +180,12 @@
178180
# component containing v1.5 nodes
179181
]
180182

183+
# this is to shorten the test name
184+
TEST_CASE_NAME_ENUMERATE = list(enumerate(map(
185+
lambda params: Path(params[0]).name,
186+
PARAMETERS_TO_TEST,
187+
)))
188+
181189

182190
def set_run_settings(node, runsettings_dict):
183191
for dot_key, value in runsettings_dict.items():

sdk/ml/azure-ai-ml/tests/internal/e2etests/test_component.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ def bodiless_matching(test_proxy):
5252

5353

5454
@pytest.mark.usefixtures(
55-
"recorded_test", "enable_internal_components", "mock_code_hash", "mock_asset_name", "mock_component_hash"
55+
"recorded_test",
56+
"enable_internal_components",
57+
"mock_code_hash",
58+
"mock_asset_name",
59+
"mock_component_hash"
5660
)
5761
@pytest.mark.e2etest
5862
@pytest.mark.pipeline_test

sdk/ml/azure-ai-ml/tests/internal/e2etests/test_pipeline_job.py

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from pathlib import Path
66
from typing import Callable
77

8-
from devtools_testutils import AzureRecordedTestCase, is_live
8+
from devtools_testutils import AzureRecordedTestCase
99
import pydash
1010
import pytest
1111

@@ -17,7 +17,7 @@
1717
from azure.core.exceptions import HttpResponseError
1818
from azure.core.polling import LROPoller
1919

20-
from .._utils import DATA_VERSION, PARAMETERS_TO_TEST, set_run_settings
20+
from .._utils import DATA_VERSION, PARAMETERS_TO_TEST, set_run_settings, TEST_CASE_NAME_ENUMERATE
2121

2222
_dependent_datasets = {}
2323

@@ -60,7 +60,6 @@ def create_internal_sample_dependent_datasets(client: MLClient):
6060
"create_internal_sample_dependent_datasets",
6161
"enable_internal_components",
6262
)
63-
@pytest.mark.skipif(condition=not is_live(), reason="Works in live mode, does not work in playback")
6463
@pytest.mark.e2etest
6564
@pytest.mark.pipeline_test
6665
class TestPipelineJob(AzureRecordedTestCase):
@@ -111,33 +110,37 @@ def pipeline_func():
111110
)
112111

113112
@pytest.mark.parametrize(
114-
"yaml_path,inputs,runsettings_dict,pipeline_runsettings_dict",
115-
PARAMETERS_TO_TEST,
113+
"test_case_i,test_case_name",
114+
TEST_CASE_NAME_ENUMERATE,
116115
)
117-
def test_pipeline_anonymous(
118-
self, client: MLClient, yaml_path, inputs, runsettings_dict, pipeline_runsettings_dict
116+
def test_pipeline_job_with_anonymous_internal_component(
117+
self,
118+
client: MLClient,
119+
test_case_i: int,
120+
test_case_name: str,
119121
):
122+
yaml_path, inputs, runsettings_dict, pipeline_runsettings_dict = PARAMETERS_TO_TEST[test_case_i]
120123
# curated env with name & version
121124
node_func: InternalComponent = load_component(yaml_path)
122125

123126
self._test_component(node_func, inputs, runsettings_dict, pipeline_runsettings_dict, client)
124127

125128
@pytest.mark.skip(reason="TODO: can't find newly registered component?")
126129
@pytest.mark.parametrize(
127-
"yaml_path,inputs,runsettings_dict,pipeline_runsettings_dict",
128-
PARAMETERS_TO_TEST,
130+
"test_case_i,test_case_name",
131+
TEST_CASE_NAME_ENUMERATE,
129132
)
130-
def test_created_internal_component_in_pipeline(
133+
def test_pipeline_job_with_registered_internal_component(
131134
self,
132135
client: MLClient,
133-
randstr: Callable[[], str],
134-
yaml_path,
135-
inputs,
136-
runsettings_dict,
137-
pipeline_runsettings_dict,
136+
randstr: Callable[[str], str],
137+
test_case_i: int,
138+
test_case_name: str,
138139
):
139-
component_to_register = load_component(yaml_path, params_override=[{"name": randstr("name")}])
140+
yaml_path, inputs, runsettings_dict, pipeline_runsettings_dict = PARAMETERS_TO_TEST[test_case_i]
140141
component_name = randstr("component_name")
142+
143+
component_to_register = load_component(yaml_path, params_override=[{"name": component_name}])
141144
component_resource = client.components.create_or_update(component_to_register)
142145

143146
created_component = client.components.get(component_name, component_resource.version)
@@ -178,23 +181,19 @@ def pipeline_func(pipeline_input):
178181
except HttpResponseError as ex:
179182
assert "CancelPipelineRunInTerminalStatus" in str(ex)
180183

181-
@pytest.mark.skip(
182-
reason="Skip for pipeline component compute bug: https://msdata.visualstudio.com/Vienna/_workitems/edit/1920464"
183-
)
184+
@pytest.mark.skip(reason="marshmallow.exceptions.ValidationError: miss required jobs.node.component")
184185
@pytest.mark.parametrize(
185-
"yaml_path,inputs,runsettings_dict,pipeline_runsettings_dict",
186-
PARAMETERS_TO_TEST,
186+
"test_case_i,test_case_name",
187+
TEST_CASE_NAME_ENUMERATE,
187188
)
188-
def test_internal_in_pipeline_component(
189+
def test_pipeline_component_with_anonymous_internal_component(
189190
self,
190191
client: MLClient,
191-
randstr: Callable[[], str],
192-
yaml_path,
193-
inputs,
194-
runsettings_dict,
195-
pipeline_runsettings_dict,
192+
test_case_i: int,
193+
test_case_name: str,
196194
):
197-
component_func = load_component(yaml_path, params_override=[{"name": randstr("name")}])
195+
yaml_path, inputs, runsettings_dict, pipeline_runsettings_dict = PARAMETERS_TO_TEST[test_case_i]
196+
component_func = load_component(yaml_path)
198197

199198
@pipeline()
200199
def sub_pipeline_func():

sdk/ml/azure-ai-ml/tests/pipeline_job/_util.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from pathlib import Path
2+
13
from azure.ai.ml.exceptions import JobException
24
from azure.core.exceptions import HttpResponseError
35

@@ -47,3 +49,9 @@
4749
),
4850
("./tests/test_configs/dsl_pipeline/data_binding_expression/run_settings_sweep_limits.yml", None),
4951
]
52+
53+
# this is to shorten the test name
54+
DATABINDING_EXPRESSION_TEST_CASE_ENUMERATE = list(enumerate(map(
55+
lambda params: Path(params[0]).name,
56+
DATABINDING_EXPRESSION_TEST_CASES,
57+
)))

sdk/ml/azure-ai-ml/tests/pipeline_job/e2etests/test_pipeline_job.py

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import json
2+
import os.path
23
import re
34
import time
45
from datetime import datetime
56
from pathlib import Path
6-
from typing import Any, Callable, Dict, Optional
7+
from typing import Any, Callable, Dict
78

8-
from devtools_testutils import AzureRecordedTestCase, is_live, set_bodiless_matcher
9+
from devtools_testutils import AzureRecordedTestCase, set_bodiless_matcher
910
import pydash
1011
import pytest
1112
from marshmallow import ValidationError
@@ -27,7 +28,8 @@
2728
from azure.core.exceptions import HttpResponseError, ResourceNotFoundError
2829
from azure.core.polling import LROPoller
2930

30-
from .._util import _PIPELINE_JOB_TIMEOUT_SECOND, DATABINDING_EXPRESSION_TEST_CASES
31+
from .._util import _PIPELINE_JOB_TIMEOUT_SECOND, DATABINDING_EXPRESSION_TEST_CASES, \
32+
DATABINDING_EXPRESSION_TEST_CASE_ENUMERATE
3133

3234

3335
def assert_job_input_output_types(job: PipelineJob):
@@ -188,35 +190,28 @@ def test_pipeline_job_get_child_run(self, client: MLClient, generate_weekly_fixe
188190
assert isinstance(retrieved_child_run, Job)
189191
assert retrieved_child_run.name == child_job.name
190192

191-
@pytest.mark.skipif(condition=not is_live(), reason="Recording file names are too long and need to be shortened")
192193
@pytest.mark.parametrize(
193-
"pipeline_job_path, expected_error_type",
194+
"pipeline_job_path",
194195
[
195196
# flaky parameterization
196-
# ("./tests/test_configs/pipeline_jobs/invalid/non_existent_remote_component.yml", Exception),
197-
(
198-
"tests/test_configs/pipeline_jobs/invalid/non_existent_remote_version.yml",
199-
Exception,
200-
),
201-
(
202-
"tests/test_configs/pipeline_jobs/invalid/non_existent_compute.yml",
203-
Exception,
204-
),
197+
# "non_existent_remote_component.yml",
198+
"non_existent_remote_version.yml",
199+
"non_existent_compute.yml",
205200
],
206201
)
207202
def test_pipeline_job_validation_remote(
208203
self,
209204
client: MLClient,
210205
randstr: Callable[[str], str],
211206
pipeline_job_path: str,
212-
expected_error_type,
213207
) -> None:
208+
base_dir = "./tests/test_configs/pipeline_jobs/invalid/"
214209
pipeline_job: PipelineJob = load_job(
215-
source=pipeline_job_path,
210+
source=os.path.join(base_dir, pipeline_job_path),
216211
params_override=[{"name": randstr("name")}],
217212
)
218213
with pytest.raises(
219-
expected_error_type,
214+
Exception,
220215
# hide this as server side error message is not consistent
221216
# match=str(expected_error),
222217
):
@@ -415,10 +410,22 @@ def test_pipeline_job_default_datastore_compute(self, client: MLClient, randstr:
415410
else:
416411
assert job.compute in pipeline_job.jobs[job_name].compute
417412

418-
@pytest.mark.skipif(condition=not is_live(), reason="Recording file names are too long and need to be shortened")
419413
@pytest.mark.parametrize(
420-
"pipeline_job_path, converted_jobs, expected_dict, fields_to_omit",
414+
"test_case_i,test_case_name",
421415
[
416+
# TODO: enable this after identity support released to canary
417+
# (0, "helloworld_pipeline_job_with_component_output"),
418+
(1, "helloworld_pipeline_job_with_paths"),
419+
]
420+
)
421+
def test_pipeline_job_with_command_job(
422+
self,
423+
client: MLClient,
424+
randstr: Callable[[str], str],
425+
test_case_i,
426+
test_case_name,
427+
) -> None:
428+
params = [
422429
(
423430
"tests/test_configs/pipeline_jobs/helloworld_pipeline_job_defaults_with_command_job_e2e.yml",
424431
2,
@@ -587,17 +594,9 @@ def test_pipeline_job_default_datastore_compute(self, client: MLClient, randstr:
587594
"source_job_id",
588595
],
589596
),
590-
],
591-
)
592-
def test_pipeline_job_with_command_job(
593-
self,
594-
client: MLClient,
595-
randstr: Callable[[str], str],
596-
pipeline_job_path: str,
597-
converted_jobs,
598-
expected_dict,
599-
fields_to_omit,
600-
) -> None:
597+
]
598+
pipeline_job_path, converted_jobs, expected_dict, fields_to_omit = params[test_case_i]
599+
601600
params_override = [{"name": randstr("name")}]
602601
pipeline_job = load_job(
603602
source=pipeline_job_path,
@@ -616,21 +615,21 @@ def test_pipeline_job_with_command_job(
616615
actual_dict = pydash.omit(pipeline_dict["properties"], *fields_to_omit)
617616
assert actual_dict == expected_dict
618617

619-
@pytest.mark.skipif(condition=not is_live(), reason="Recording file names are too long and need to be shortened")
620618
@pytest.mark.parametrize(
621619
"pipeline_job_path",
622620
[
623-
"tests/test_configs/pipeline_jobs/helloworld_pipeline_job_defaults_with_parallel_job_file_component_input_e2e.yml",
624-
"tests/test_configs/pipeline_jobs/helloworld_pipeline_job_defaults_with_parallel_job_file_input_e2e.yml",
625-
"tests/test_configs/pipeline_jobs/helloworld_pipeline_job_defaults_with_parallel_job_tabular_input_e2e.yml",
621+
"file_component_input_e2e.yml",
622+
"file_input_e2e.yml",
623+
"tabular_input_e2e.yml",
626624
],
627625
)
628626
def test_pipeline_job_with_parallel_job(
629627
self, client: MLClient, randstr: Callable[[str], str], pipeline_job_path: str
630628
) -> None:
629+
base_file_name = "./tests/test_configs/pipeline_jobs/helloworld_pipeline_job_defaults_with_parallel_job_"
631630
params_override = [{"name": randstr("name")}]
632631
pipeline_job = load_job(
633-
source=pipeline_job_path,
632+
source=base_file_name + pipeline_job_path,
634633
params_override=params_override,
635634
)
636635
created_job = client.jobs.create_or_update(pipeline_job)
@@ -942,18 +941,19 @@ def test_pipeline_job_with_sweep_node_early_termination_policy(
942941
created_pipeline_dict = created_pipeline._to_dict()
943942
assert pydash.get(created_pipeline_dict, "jobs.hello_sweep_inline_trial.early_termination") == policy_yaml_dict
944943

945-
@pytest.mark.skipif(condition=not is_live(), reason="Recording file names are too long and need to be shortened")
946944
@pytest.mark.parametrize(
947-
"pipeline_job_path, expected_error",
948-
DATABINDING_EXPRESSION_TEST_CASES,
945+
"test_case_i, test_case_name",
946+
DATABINDING_EXPRESSION_TEST_CASE_ENUMERATE,
949947
)
950948
def test_pipeline_job_with_data_binding_expression(
951949
self,
952950
client: MLClient,
953951
randstr: Callable[[str], str],
954-
pipeline_job_path: str,
955-
expected_error: Optional[Exception],
952+
test_case_i: int,
953+
test_case_name: str,
956954
):
955+
pipeline_job_path, expected_error = DATABINDING_EXPRESSION_TEST_CASES[test_case_i]
956+
957957
pipeline: PipelineJob = load_job(source=pipeline_job_path, params_override=[{"name": randstr("name")}])
958958
if expected_error is None:
959959
assert_job_cancel(pipeline, client)

0 commit comments

Comments
 (0)