|
23 | 23 | from mock import ANY, MagicMock, Mock, patch, call, mock_open
|
24 | 24 |
|
25 | 25 | import sagemaker
|
26 |
| -from sagemaker import TrainingInput, Session, get_execution_role |
| 26 | +from sagemaker import TrainingInput, Session, get_execution_role, exceptions |
27 | 27 | from sagemaker.async_inference import AsyncInferenceConfig
|
28 | 28 | from sagemaker.session import (
|
29 | 29 | _tuning_job_status,
|
@@ -2267,7 +2267,6 @@ def test_train_done_in_progress(sagemaker_session):
|
2267 | 2267 | "GenerateCandidateDefinitionsOnly": False,
|
2268 | 2268 | }
|
2269 | 2269 |
|
2270 |
| - |
2271 | 2270 | COMPLETE_EXPECTED_AUTO_ML_JOB_ARGS = {
|
2272 | 2271 | "AutoMLJobName": JOB_NAME,
|
2273 | 2272 | "InputDataConfig": [
|
@@ -3112,3 +3111,160 @@ def test_create_inference_recommendations_job_propogate_other_exception(sagemake
|
3112 | 3111 | )
|
3113 | 3112 |
|
3114 | 3113 | assert "AccessDeniedException" in str(error)
|
| 3114 | + |
| 3115 | + |
| 3116 | +DEFAULT_LOG_EVENTS_INFERENCE_RECOMMENDER = [ |
| 3117 | + MockBotoException("ResourceNotFoundException"), |
| 3118 | + {"nextForwardToken": None, "events": [{"timestamp": 1, "message": "hi there #1"}]}, |
| 3119 | + {"nextForwardToken": None, "events": [{"timestamp": 2, "message": "hi there #2"}]}, |
| 3120 | + {"nextForwardToken": None, "events": [{"timestamp": 3, "message": "hi there #3"}]}, |
| 3121 | + {"nextForwardToken": None, "events": [{"timestamp": 4, "message": "hi there #4"}]}, |
| 3122 | +] |
| 3123 | + |
| 3124 | +FLUSH_LOG_EVENTS_INFERENCE_RECOMMENDER = [ |
| 3125 | + MockBotoException("ResourceNotFoundException"), |
| 3126 | + {"nextForwardToken": None, "events": [{"timestamp": 1, "message": "hi there #1"}]}, |
| 3127 | + {"nextForwardToken": None, "events": [{"timestamp": 2, "message": "hi there #2"}]}, |
| 3128 | + {"nextForwardToken": None, "events": []}, |
| 3129 | + {"nextForwardToken": None, "events": [{"timestamp": 3, "message": "hi there #3"}]}, |
| 3130 | + {"nextForwardToken": None, "events": []}, |
| 3131 | + {"nextForwardToken": None, "events": [{"timestamp": 4, "message": "hi there #4"}]}, |
| 3132 | +] |
| 3133 | + |
| 3134 | +INFERENCE_RECOMMENDATIONS_DESC_STATUS_PENDING = {"Status": "PENDING"} |
| 3135 | +INFERENCE_RECOMMENDATIONS_DESC_STATUS_IN_PROGRESS = {"Status": "IN_PROGRESS"} |
| 3136 | +INFERENCE_RECOMMENDATIONS_DESC_STATUS_COMPLETED = {"Status": "COMPLETED"} |
| 3137 | + |
| 3138 | + |
| 3139 | +@pytest.fixture() |
| 3140 | +def sm_session_inference_recommender(): |
| 3141 | + boto_mock = MagicMock(name="boto_session") |
| 3142 | + boto_mock.client("logs").get_log_events.side_effect = DEFAULT_LOG_EVENTS_INFERENCE_RECOMMENDER |
| 3143 | + |
| 3144 | + ims = sagemaker.Session(boto_session=boto_mock, sagemaker_client=MagicMock()) |
| 3145 | + |
| 3146 | + ims.sagemaker_client.describe_inference_recommendations_job.side_effect = [ |
| 3147 | + INFERENCE_RECOMMENDATIONS_DESC_STATUS_PENDING, |
| 3148 | + INFERENCE_RECOMMENDATIONS_DESC_STATUS_IN_PROGRESS, |
| 3149 | + INFERENCE_RECOMMENDATIONS_DESC_STATUS_COMPLETED, |
| 3150 | + INFERENCE_RECOMMENDATIONS_DESC_STATUS_COMPLETED, |
| 3151 | + ] |
| 3152 | + |
| 3153 | + return ims |
| 3154 | + |
| 3155 | + |
| 3156 | +@pytest.fixture() |
| 3157 | +def sm_session_inference_recommender_flush(): |
| 3158 | + boto_mock = MagicMock(name="boto_session") |
| 3159 | + boto_mock.client("logs").get_log_events.side_effect = FLUSH_LOG_EVENTS_INFERENCE_RECOMMENDER |
| 3160 | + |
| 3161 | + ims = sagemaker.Session(boto_session=boto_mock, sagemaker_client=MagicMock()) |
| 3162 | + |
| 3163 | + ims.sagemaker_client.describe_inference_recommendations_job.side_effect = [ |
| 3164 | + INFERENCE_RECOMMENDATIONS_DESC_STATUS_PENDING, |
| 3165 | + INFERENCE_RECOMMENDATIONS_DESC_STATUS_IN_PROGRESS, |
| 3166 | + INFERENCE_RECOMMENDATIONS_DESC_STATUS_IN_PROGRESS, |
| 3167 | + INFERENCE_RECOMMENDATIONS_DESC_STATUS_COMPLETED, |
| 3168 | + INFERENCE_RECOMMENDATIONS_DESC_STATUS_COMPLETED, |
| 3169 | + INFERENCE_RECOMMENDATIONS_DESC_STATUS_COMPLETED, |
| 3170 | + ] |
| 3171 | + |
| 3172 | + return ims |
| 3173 | + |
| 3174 | + |
| 3175 | +@patch("time.sleep") |
| 3176 | +def test_wait_for_inference_recommendations_job_completed(sleep, sm_session_inference_recommender): |
| 3177 | + assert ( |
| 3178 | + sm_session_inference_recommender.wait_for_inference_recommendations_job( |
| 3179 | + JOB_NAME, log_level="Quiet" |
| 3180 | + )["Status"] |
| 3181 | + == "COMPLETED" |
| 3182 | + ) |
| 3183 | + |
| 3184 | + assert ( |
| 3185 | + 4 |
| 3186 | + == sm_session_inference_recommender.sagemaker_client.describe_inference_recommendations_job.call_count |
| 3187 | + ) |
| 3188 | + assert 2 == sleep.call_count |
| 3189 | + sleep.assert_has_calls([call(120), call(120)]) |
| 3190 | + |
| 3191 | + |
| 3192 | +def test_wait_for_inference_recommendations_job_failed(sagemaker_session): |
| 3193 | + inference_recommendations_desc_status_failed = { |
| 3194 | + "Status": "FAILED", |
| 3195 | + "FailureReason": "Mock Failure Reason", |
| 3196 | + } |
| 3197 | + |
| 3198 | + sagemaker_session.sagemaker_client.describe_inference_recommendations_job = Mock( |
| 3199 | + name="describe_inference_recommendations_job", |
| 3200 | + return_value=inference_recommendations_desc_status_failed, |
| 3201 | + ) |
| 3202 | + |
| 3203 | + with pytest.raises(exceptions.UnexpectedStatusException) as error: |
| 3204 | + sagemaker_session.wait_for_inference_recommendations_job(JOB_NAME) |
| 3205 | + |
| 3206 | + assert "Mock Failure Reason" in str(error) |
| 3207 | + |
| 3208 | + |
| 3209 | +@patch("builtins.print") |
| 3210 | +@patch("time.sleep") |
| 3211 | +def test_wait_for_inference_recommendations_job_completed_verbose( |
| 3212 | + sleep, mock_print, sm_session_inference_recommender |
| 3213 | +): |
| 3214 | + assert ( |
| 3215 | + sm_session_inference_recommender.wait_for_inference_recommendations_job( |
| 3216 | + JOB_NAME, log_level="Verbose" |
| 3217 | + )["Status"] |
| 3218 | + == "COMPLETED" |
| 3219 | + ) |
| 3220 | + assert ( |
| 3221 | + 4 |
| 3222 | + == sm_session_inference_recommender.sagemaker_client.describe_inference_recommendations_job.call_count |
| 3223 | + ) |
| 3224 | + |
| 3225 | + assert ( |
| 3226 | + 5 == sm_session_inference_recommender.boto_session.client("logs").get_log_events.call_count |
| 3227 | + ) |
| 3228 | + |
| 3229 | + assert 3 == sleep.call_count |
| 3230 | + sleep.assert_has_calls([call(10), call(60), call(60)]) |
| 3231 | + |
| 3232 | + assert 8 == mock_print.call_count |
| 3233 | + |
| 3234 | + |
| 3235 | +@patch("builtins.print") |
| 3236 | +@patch("time.sleep") |
| 3237 | +def test_wait_for_inference_recommendations_job_flush_completed( |
| 3238 | + sleep, mock_print, sm_session_inference_recommender_flush |
| 3239 | +): |
| 3240 | + assert ( |
| 3241 | + sm_session_inference_recommender_flush.wait_for_inference_recommendations_job( |
| 3242 | + JOB_NAME, log_level="Verbose" |
| 3243 | + )["Status"] |
| 3244 | + == "COMPLETED" |
| 3245 | + ) |
| 3246 | + assert ( |
| 3247 | + 6 |
| 3248 | + == sm_session_inference_recommender_flush.sagemaker_client.describe_inference_recommendations_job.call_count |
| 3249 | + ) |
| 3250 | + |
| 3251 | + assert ( |
| 3252 | + 7 |
| 3253 | + == sm_session_inference_recommender_flush.boto_session.client( |
| 3254 | + "logs" |
| 3255 | + ).get_log_events.call_count |
| 3256 | + ) |
| 3257 | + |
| 3258 | + assert 5 == sleep.call_count |
| 3259 | + sleep.assert_has_calls([call(10), call(60), call(60), call(60), call(60)]) |
| 3260 | + |
| 3261 | + assert 8 == mock_print.call_count |
| 3262 | + |
| 3263 | + |
| 3264 | +def test_wait_for_inference_recommendations_job_invalid_log_level(sagemaker_session): |
| 3265 | + with pytest.raises(ValueError) as error: |
| 3266 | + sagemaker_session.wait_for_inference_recommendations_job( |
| 3267 | + JOB_NAME, log_level="invalid_log_level" |
| 3268 | + ) |
| 3269 | + |
| 3270 | + assert "log_level must be either Quiet or Verbose" in str(error) |
0 commit comments