Skip to content

Commit 36e3771

Browse files
committed
Adds ability to handle error messages that are URLs.
1 parent f990e54 commit 36e3771

File tree

3 files changed

+102
-2
lines changed

3 files changed

+102
-2
lines changed

cloudpub/aws/service.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
1111
from tenacity.wait import wait_fixed
1212

1313
from cloudpub.aws.utils import (
14+
convert_error_list_str,
1415
create_version_tree,
1516
get_restricted_major_versions,
1617
get_restricted_minor_versions,
1718
get_restricted_patch_versions,
19+
get_text_url,
20+
is_str_url,
1821
pprint_debug_logging,
1922
)
2023
from cloudpub.common import BaseService, PublishingMetadata
@@ -386,8 +389,15 @@ def check_publish_status(self, change_set_id: str) -> str:
386389
# the first one should be the one we want.
387390
failure_list = rsp.change_set[0].error_details
388391
pprint_debug_logging(log, rsp, "The response from the status was: ")
392+
# Check if message is a URL and download the message.
393+
added_messages = []
394+
for failure in failure_list:
395+
if is_str_url(failure.message):
396+
added_messages.extend(get_text_url(failure.message))
397+
failure_list.extend(added_messages)
398+
error_list_str = convert_error_list_str(failure_list)
389399
error_message = (
390-
f"Changeset {change_set_id} failed with code {failure_code}: \n {failure_list}"
400+
f"Changeset {change_set_id} failed with code {failure_code}: \n {error_list_str}"
391401
)
392402
self._raise_error(InvalidStateError, error_message)
393403

cloudpub/aws/utils.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
# SPDX-License-Identifier: GPL-3.0-or-later
2+
import json
23
import logging
4+
import re
35
from pprint import pformat
46
from typing import Any, Dict, List, Mapping, Tuple
57

68
import dateutil.parser
9+
import requests
710
from packaging.version import InvalidVersion, Version
811

9-
from cloudpub.models.aws import GroupedVersions
12+
from cloudpub.models.aws import ErrorDetail, GroupedVersions
1013

1114

1215
def create_version_tree(versions: Dict[str, GroupedVersions]) -> Dict[str, Any]:
@@ -141,3 +144,52 @@ def pprint_debug_logging(
141144
"""
142145
if log.isEnabledFor(logging.DEBUG):
143146
log.debug("%s\n%s", log_tag, pformat(rsp_log))
147+
148+
149+
def is_str_url(url_str: str) -> bool:
150+
"""
151+
Check if string is a URL.
152+
153+
Args:
154+
url_str (str)
155+
A string represenation of a URL.
156+
Returns:
157+
Bool
158+
"""
159+
pattern = r"^https:\/\/[0-9A-z.]+.[0-9A-z.]+.[a-z]+$"
160+
result = re.match(pattern, url_str)
161+
return result
162+
163+
164+
def get_text_url(url: str) -> List[ErrorDetail]:
165+
"""
166+
Get text from remote URL.
167+
168+
Args:
169+
url (str)
170+
The url that the messsage is stored at.
171+
Returns:
172+
List[ErrorDetail]
173+
"""
174+
resp = requests.get(url)
175+
data = json.loads(resp.text)
176+
error_list = []
177+
for e in data:
178+
error_list.append(ErrorDetail.from_json(e))
179+
return error_list
180+
181+
182+
def convert_error_list_str(error_list: List[ErrorDetail]) -> List[Dict[str, Any]]:
183+
"""
184+
Convert a list of ErrorDetail to json str.
185+
186+
Args:
187+
error_list (List[ErrorDetail])
188+
A list of ErrorDetails.
189+
Returns:
190+
List[Dict[str, Any]]
191+
"""
192+
error_str_list = []
193+
for e in error_list:
194+
error_str_list.append(e.to_json())
195+
return error_str_list

tests/aws/test_service.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import pytest
88
from _pytest.logging import LogCaptureFixture
9+
from httmock import HTTMock, urlmatch
910

1011
from cloudpub.aws import AWSProductService, AWSVersionMetadata
1112
from cloudpub.error import InvalidStateError, NotFoundError, Timeout
@@ -477,6 +478,43 @@ def test_check_publish_status_failed(
477478
with pytest.raises(InvalidStateError):
478479
_ = aws_service.check_publish_status("fake-change-set-id")
479480

481+
def test_check_publish_status_failed_url(
482+
self, mock_describe_change_set: mock.MagicMock, aws_service: AWSProductService
483+
) -> None:
484+
@urlmatch(netloc=r'(.*\.)?fake\.com$')
485+
def request_mock(url, request):
486+
error_list = [{"ErrorCode": "EOL", "ErrorMessage": "some text"}]
487+
return json.dumps(error_list)
488+
489+
failure_list = [
490+
{
491+
"ErrorCode": "SCAN_ERROR",
492+
"ErrorMessage": "https://www.fake.com/error-message",
493+
}
494+
]
495+
change_set = [
496+
{
497+
"ChangeType": "RestrictDeliveryOptions",
498+
"Details": r"{}",
499+
"ErrorDetailList": failure_list,
500+
}
501+
]
502+
ret = {
503+
"ChangeSetId": "change",
504+
"ChangeSetArn": "fake-arn",
505+
"Status": "Failed",
506+
"FailureCode": "fake-code",
507+
"ChangeSet": change_set,
508+
"StartTime": "fake-start-time",
509+
"EndTime": "fake-end-time",
510+
}
511+
mock_describe_change_set.return_value = ret
512+
with HTTMock(request_mock):
513+
with pytest.raises(InvalidStateError) as error:
514+
aws_service.check_publish_status("fake-change-set-id")
515+
assert "https://www.fake.com/error-message" in str(error)
516+
assert "EOL" in str(error)
517+
480518
def test_wait_for_changeset(
481519
self, mock_describe_change_set: mock.MagicMock, aws_service: AWSProductService
482520
) -> None:

0 commit comments

Comments
 (0)