Skip to content

Commit 5432cc2

Browse files
authored
test: enable internal pipeline job e2e tests (Azure#27214)
* test: enable internal pipeline job e2e tests * refactor: apply new cancel util to more tests * refactor: update cancel logic for import job tests
1 parent 934be7e commit 5432cc2

File tree

16 files changed

+176
-281
lines changed

16 files changed

+176
-281
lines changed

sdk/ml/azure-ai-ml/tests/batch_services/e2etests/test_batch_deployment.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import time
21
import uuid
32
from contextlib import contextmanager
43
from pathlib import Path
@@ -10,11 +9,11 @@
109
from azure.ai.ml import MLClient, load_batch_deployment, load_batch_endpoint, load_environment, load_model
1110
from azure.ai.ml._utils._arm_id_utils import AMLVersionedArmId
1211
from azure.ai.ml.constants._common import AssetTypes
13-
from azure.ai.ml.entities import BatchDeployment, BatchEndpoint, Job
12+
from azure.ai.ml.entities import BatchDeployment, BatchEndpoint
1413
from azure.ai.ml.entities._inputs_outputs import Input
15-
from azure.ai.ml.operations._job_ops_helper import _wait_before_polling
16-
from azure.ai.ml.operations._run_history_constants import JobStatus, RunHistoryConstants
17-
from azure.core.polling import LROPoller
14+
from azure.ai.ml.operations._run_history_constants import JobStatus
15+
16+
from test_utilities.utils import wait_until_done
1817

1918

2019
@contextmanager
@@ -137,19 +136,6 @@ def test_batch_deployment_dependency_label_resolution(self, client: MLClient, ra
137136

138137
@pytest.mark.e2etest
139138
def test_batch_job_download(self, client: MLClient, tmp_path: Path) -> str:
140-
def wait_until_done(job: Job, timeout: int = None) -> None:
141-
poll_start_time = time.time()
142-
while job.status not in RunHistoryConstants.TERMINAL_STATUSES:
143-
time.sleep(_wait_before_polling(time.time() - poll_start_time))
144-
job = client.jobs.get(job.name)
145-
if timeout is not None and time.time() - poll_start_time > timeout:
146-
# if timeout is passed in, execute job cancel if timeout and directly return CANCELED status
147-
cancel_poller = client.jobs.begin_cancel(job.name)
148-
assert isinstance(cancel_poller, LROPoller)
149-
assert cancel_poller.result() is None
150-
return JobStatus.CANCELED
151-
return job.status
152-
153139
endpoint = load_batch_endpoint(
154140
"./tests/test_configs/endpoints/batch/batch_endpoint_mlflow_new.yaml",
155141
params_override=[{"name": "batch-ept-" + uuid.uuid4().hex[:15]}],
@@ -174,7 +160,7 @@ def wait_until_done(job: Job, timeout: int = None) -> None:
174160
# Adding a timeout value of 5 minutes to avoid future scenarios where wait
175161
# long periods for the test to finish. Instead if the job takes longer
176162
# than 5 minutes to finish we will make the test fail
177-
job_status = wait_until_done(batchjob, 300)
163+
job_status = wait_until_done(job=batchjob, client=client, timeout=300)
178164

179165
# Check if the job was canceled due to a timeout.
180166
# If the job's status is CANCELED, we will make the test fail

sdk/ml/azure-ai-ml/tests/command_job/e2etests/test_command_job.py

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import time
21
from pathlib import Path
32
from time import sleep
43
from typing import Callable
54

65
from azure.ai.ml.entities import AmlTokenConfiguration
7-
from devtools_testutils import AzureRecordedTestCase, is_live, set_bodiless_matcher
6+
from devtools_testutils import AzureRecordedTestCase, is_live
87
import jwt
98
import pytest
109

@@ -18,19 +17,17 @@
1817
from azure.ai.ml.entities._job.distribution import MpiDistribution
1918
from azure.ai.ml.entities._job.job import Job
2019
from azure.ai.ml.exceptions import ValidationException
21-
from azure.ai.ml.operations._job_ops_helper import _wait_before_polling
2220
from azure.ai.ml.operations._run_history_constants import JobStatus, RunHistoryConstants
2321
from azure.core.polling import LROPoller
2422

23+
from test_utilities.utils import wait_until_done
24+
2525
# These params are logged in ..\test_configs\python\simple_train.py. test_command_job_with_params asserts these parameters are
2626
# logged in the training script, so any changes to parameter logging in simple_train.py must preserve this logging or change it both
2727
# here and in the script.
2828
TEST_PARAMS = {"a_param": "1", "another_param": "2"}
2929

30-
31-
@pytest.mark.fixture(autouse=True)
32-
def bodiless_matching(test_proxy):
33-
set_bodiless_matcher()
30+
# previous bodiless_matcher fixture doesn't take effect because of typo, please add it in method level if needed
3431

3532

3633
@pytest.mark.timeout(600)
@@ -345,19 +342,13 @@ def get_job_list():
345342
def test_command_job_download(self, tmp_path: Path, randstr: Callable[[], str], client: MLClient) -> None:
346343
client: MLClient = client
347344

348-
def wait_until_done(job: Job) -> None:
349-
poll_start_time = time.time()
350-
while job.status not in RunHistoryConstants.TERMINAL_STATUSES:
351-
time.sleep(_wait_before_polling(time.time() - poll_start_time))
352-
job = client.jobs.get(job.name)
353-
354345
job = client.jobs.create_or_update(
355346
load_job(
356347
source="./tests/test_configs/command_job/command_job_quick_with_output.yml",
357348
params_override=[{"name": randstr("name")}],
358349
)
359350
)
360-
wait_until_done(job)
351+
wait_until_done(client=client, job=job)
361352

362353
client.jobs.download(name=job.name, download_path=tmp_path, all=True)
363354

@@ -374,20 +365,14 @@ def wait_until_done(job: Job) -> None:
374365
def test_command_job_local_run_download(self, tmp_path: Path, randstr: Callable[[], str], client: MLClient) -> None:
375366
client: MLClient = client
376367

377-
def wait_until_done(job: Job) -> None:
378-
poll_start_time = time.time()
379-
while job.status not in RunHistoryConstants.TERMINAL_STATUSES:
380-
time.sleep(_wait_before_polling(time.time() - poll_start_time))
381-
job = client.jobs.get(job.name)
382-
383368
job = client.jobs.create_or_update(
384369
load_job(
385370
source="./tests/test_configs/command_job/command_job_quick_with_output.yml",
386371
params_override=[{"name": randstr("name")}, {"compute": LOCAL_COMPUTE_TARGET}],
387372
)
388373
)
389374

390-
wait_until_done(job)
375+
wait_until_done(client=client, job=job)
391376

392377
client.jobs.download(name=job.name, download_path=tmp_path, all=True)
393378

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

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import pytest
1010

1111
from azure.ai.ml import MLClient, MpiDistribution, load_component, load_environment
12-
from azure.ai.ml._restclient.v2022_05_01.models import ComponentContainerData, ListViewType
12+
from azure.ai.ml._restclient.v2022_05_01.models import ListViewType
1313
from azure.ai.ml._utils._arm_id_utils import is_ARM_id_for_resource
1414
from azure.ai.ml.constants._common import (
1515
ANONYMOUS_COMPONENT_NAME,
@@ -22,8 +22,8 @@
2222
from azure.ai.ml.entities._load_functions import load_code, load_job
2323
from azure.core.exceptions import HttpResponseError, ResourceNotFoundError
2424
from azure.core.paging import ItemPaged
25-
from azure.core.polling import LROPoller
2625

26+
from test_utilities.utils import assert_job_cancel
2727
from .._util import _COMPONENT_TIMEOUT_SECOND
2828
from ..unittests.test_component_schema import load_component_entity_from_rest_json
2929

@@ -84,10 +84,7 @@ def create_tensorflow_distribution(has_strs: bool = False):
8484

8585
return create_tensorflow_distribution
8686

87-
88-
@pytest.mark.fixture(autouse=True)
89-
def bodiless_matching(test_proxy):
90-
set_bodiless_matcher()
87+
# previous bodiless_matcher fixture doesn't take effect because of typo, please add it in method level if needed
9188

9289

9390
def assert_component_basic_workflow(
@@ -839,13 +836,7 @@ def test_create_pipeline_component_from_job(self, client: MLClient, randstr: Cal
839836
"./tests/test_configs/dsl_pipeline/pipeline_with_pipeline_component/pipeline.yml",
840837
params_override=params_override,
841838
)
842-
job = client.jobs.create_or_update(pipeline_job)
843-
try:
844-
cancel_poller = client.jobs.begin_cancel(job.name)
845-
assert isinstance(cancel_poller, LROPoller)
846-
assert cancel_poller.result() is None
847-
except Exception:
848-
pass
839+
job = assert_job_cancel(pipeline_job, client)
849840
name = randstr("component_name_1")
850841
component = PipelineComponent(name=name, source_job_id=job.id)
851842
rest_component = client.components.create_or_update(component)

sdk/ml/azure-ai-ml/tests/conftest.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@
3030
add_remove_header_sanitizer,
3131
is_live,
3232
set_custom_default_matcher,
33-
test_proxy,
33+
set_bodiless_matcher,
3434
)
3535
from devtools_testutils.fake_credentials import FakeTokenCredential
3636
from devtools_testutils.helpers import is_live_and_not_recording
37-
from devtools_testutils.proxy_fixtures import VariableRecorder, variable_recorder
37+
from devtools_testutils.proxy_fixtures import VariableRecorder
3838
from pytest_mock import MockFixture
3939

4040
from test_utilities.constants import Test_Registry_Name, Test_Resource_Group, Test_Subscription, Test_Workspace_Name
@@ -555,3 +555,22 @@ def enable_internal_components():
555555
with environment_variable_overwrite(AZUREML_INTERNAL_COMPONENTS_ENV_VAR, "True"):
556556
# need to call _try_init_internal_components manually as environment variable is set after _internal is imported
557557
try_enable_internal_components()
558+
559+
560+
@pytest.fixture()
561+
def bodiless_matching(test_proxy):
562+
set_bodiless_matcher()
563+
564+
565+
def pytest_configure(config):
566+
# register customized pytest markers
567+
for marker, description in [
568+
("e2etest", "marks tests as end to end tests, which involve requests to the server"),
569+
("unittest", "marks tests as unit tests, which do not involve requests to the server"),
570+
("pipeline_test", "marks tests as pipeline tests, which will create pipeline jobs during testing"),
571+
("automl_test", "marks tests as automl tests, which will create automl jobs during testing"),
572+
("production_experience_test", "marks tests as production experience tests"),
573+
]:
574+
config.addinivalue_line("markers", f"{marker}: {description}")
575+
576+
config.addinivalue_line("markers", f"{marker}: {description}")

sdk/ml/azure-ai-ml/tests/dataset/e2etests/test_data.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,9 @@
1111
from azure.core.paging import ItemPaged
1212

1313

14-
from devtools_testutils import AzureRecordedTestCase, set_bodiless_matcher
14+
from devtools_testutils import AzureRecordedTestCase
1515

16-
17-
@pytest.mark.fixture(autouse=True)
18-
def bodiless_matching(test_proxy):
19-
set_bodiless_matcher()
16+
# previous bodiless_matcher fixture doesn't take effect because of typo, please add it in method level if needed
2017

2118

2219
@pytest.mark.e2etest

sdk/ml/azure-ai-ml/tests/dsl/e2etests/test_dsl_pipeline.py

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,9 @@
2929
from azure.ai.ml.entities import Data, PipelineJob
3030
from azure.ai.ml.exceptions import ValidationException
3131
from azure.ai.ml.parallel import ParallelJob, RunFunction, parallel_run_function
32-
from azure.core.exceptions import HttpResponseError
33-
from azure.core.polling import LROPoller
3432
from devtools_testutils import AzureRecordedTestCase
3533
from pipeline_job.e2etests.test_pipeline_job import assert_job_input_output_types
36-
from test_utilities.utils import _PYTEST_TIMEOUT_METHOD, omit_with_wildcard
34+
from test_utilities.utils import _PYTEST_TIMEOUT_METHOD, omit_with_wildcard, assert_job_cancel
3735

3836
from .._util import _DSL_TIMEOUT_SECOND
3937

@@ -57,18 +55,6 @@
5755
]
5856

5957

60-
def assert_job_cancel(pipeline, client: MLClient, experiment_name=None):
61-
job = client.jobs.create_or_update(pipeline, experiment_name=experiment_name)
62-
try:
63-
cancel_poller = client.jobs.begin_cancel(job.name)
64-
assert isinstance(cancel_poller, LROPoller)
65-
# skip wait for cancel result to reduce test run duration.
66-
# assert cancel_poller.result() is None
67-
except HttpResponseError:
68-
pass
69-
return job
70-
71-
7258
@pytest.mark.usefixtures(
7359
"enable_environment_id_arm_expansion",
7460
"enable_pipeline_private_preview_features",

sdk/ml/azure-ai-ml/tests/dsl/e2etests/test_dsl_pipeline_on_registry.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,17 @@
11
import pytest
22
from pathlib import Path
3-
from test_utilities.utils import _PYTEST_TIMEOUT_METHOD
3+
from test_utilities.utils import _PYTEST_TIMEOUT_METHOD, assert_job_cancel
44

55
from azure.ai.ml import MLClient, load_component, Input, load_model
66
from azure.ai.ml.dsl import pipeline
77
from azure.ai.ml.constants import AssetTypes
88
from azure.core.exceptions import HttpResponseError, ResourceNotFoundError
9-
from azure.core.polling import LROPoller
109

1110
from .._util import _DSL_TIMEOUT_SECOND
1211

1312
from devtools_testutils import AzureRecordedTestCase
1413

1514

16-
def assert_job_cancel(pipeline, client: MLClient, experiment_name=None):
17-
job = client.jobs.create_or_update(pipeline, experiment_name=experiment_name)
18-
try:
19-
cancel_poller = client.jobs.begin_cancel(job.name)
20-
assert isinstance(cancel_poller, LROPoller)
21-
# skip wait for cancel result to reduce test run duration.
22-
# assert cancel_poller.result() is None
23-
except HttpResponseError:
24-
pass
25-
return job
26-
27-
2815
@pytest.mark.usefixtures("enable_pipeline_private_preview_features", "recorded_test")
2916
@pytest.mark.timeout(timeout=_DSL_TIMEOUT_SECOND, method=_PYTEST_TIMEOUT_METHOD)
3017
@pytest.mark.e2etest

0 commit comments

Comments
 (0)