Skip to content

Commit

Permalink
feat: added dry-run mode for content_metadata transmitter (#1883)
Browse files Browse the repository at this point in the history
  • Loading branch information
zamanafzal authored Oct 4, 2023
1 parent b55a05b commit d7b31f4
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Change Log
Unreleased
----------
[4.5.3]
-------
feat: added dry run mode for content metadata transmission

[4.5.2]
-------
chore: adding a more flexible way of fetching api request data
Expand Down
2 changes: 1 addition & 1 deletion enterprise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Your project description goes here.
"""

__version__ = "4.5.2"
__version__ = "4.5.3"
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from integrated_channels.exceptions import ClientError
from integrated_channels.integrated_channel.client import IntegratedChannelApiClient
from integrated_channels.integrated_channel.transmitters import Transmitter
from integrated_channels.utils import chunks, generate_formatted_log
from integrated_channels.utils import chunks, encode_binary_data_for_logging, generate_formatted_log

LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -153,6 +153,24 @@ def _transmit_action(self, content_metadata_item_map, client_method, action_name
for chunk in islice(chunk_items, transmission_limit):
json_payloads = [item.channel_metadata for item in list(chunk.values())]
serialized_chunk = self._serialize_items(json_payloads)
if self.enterprise_configuration.dry_run_mode_enabled:
enterprise_customer_uuid = self.enterprise_configuration.enterprise_customer.uuid
channel_code = self.enterprise_configuration.channel_code()
for key, item in chunk.items():
payload = item.channel_metadata
serialized_payload = self._serialize_items([payload])
encoded_serialized_payload = encode_binary_data_for_logging(serialized_payload)
LOGGER.info(generate_formatted_log(
channel_code,
enterprise_customer_uuid,
None,
key,
f'dry-run mode content metadata '
f'skipping "{action_name}" action for content metadata transmission '
f'integrated_channel_serialized_payload_base64={encoded_serialized_payload}'
))
continue

response_status_code = None
response_body = None
try:
Expand Down
15 changes: 15 additions & 0 deletions integrated_channels/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ def encode_data_for_logging(data):
return base64.urlsafe_b64encode(data.encode("utf-8")).decode('utf-8')


def encode_binary_data_for_logging(data):
"""
Converts binary input into URL-safe, utf-8 encoded, base64 encoded output.
If the input is binary (bytes), it is first decoded to utf-8, then dumped to JSON,
and finally, base64 encoded.
"""
if not isinstance(data, str):
try:
data = json.dumps(data.decode('utf-8'))
except (UnicodeDecodeError, AttributeError):
# Handle decoding errors or attribute errors (e.g., if 'data' is not bytes)
data = json.dumps(data)
return base64.urlsafe_b64encode(data.encode("utf-8")).decode('utf-8')


def parse_datetime_to_epoch(datestamp, magnitude=1.0):
"""
Convert an ISO-8601 datetime string to a Unix epoch timestamp in some magnitude.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,3 +490,34 @@ def test_transmit_success_resolve_orphaned_content(self):

orphaned_content_record.refresh_from_db()
assert orphaned_content_record.resolved

def test_content_data_transmission_dry_run_mode(self):
"""
Test that a customer's configuration can run in dry run mode
"""
# Set feature flag to true
self.enterprise_config.dry_run_mode_enabled = True

content_id_1 = 'course:DemoX'
channel_metadata_1 = {'update': True}
content_1 = factories.ContentMetadataItemTransmissionFactory(
content_id=content_id_1,
enterprise_customer=self.enterprise_config.enterprise_customer,
plugin_configuration_id=self.enterprise_config.id,
integrated_channel_code=self.enterprise_config.channel_code(),
enterprise_customer_catalog_uuid=self.enterprise_catalog.uuid,
channel_metadata=channel_metadata_1,
remote_created_at=datetime.utcnow()
)

create_payload = {}
update_payload = {}
delete_payload = {content_id_1: content_1}
self.delete_content_metadata_mock.return_value = (self.success_response_code, self.success_response_body)
transmitter = ContentMetadataTransmitter(self.enterprise_config)
transmitter.transmit(create_payload, update_payload, delete_payload)

# with dry_run_mode_enabled = True we shouldn't be able to call these methods
self.create_content_metadata_mock.assert_not_called()
self.update_content_metadata_mock.assert_not_called()
self.delete_content_metadata_mock.assert_not_called()

0 comments on commit d7b31f4

Please sign in to comment.