import csv import datetime from decimal import Decimal from unittest.mock import Mock import application from flexmock import flexmock from freezegun import freeze_time from oto import response import pytest from requests import models import simplejson as json from masters_registry import utils def test_flaskify_dict_response(): """Test flaskifying a response. """ resp = utils.flaskify(response.Response(message=dict(key='value'))) assert resp.data == b'{"key": "value"}' assert resp.mimetype == 'application/json' assert resp.status_code == 200 def test_flaskify_list_response(): """Test flaskifying a response. """ resp = utils.flaskify(response.Response(message=['value1', Decimal('42')])) assert resp.data == b'["value1", 42]' assert resp.mimetype == 'application/json' assert resp.status_code == 200 def test_flaskify_string_response(): """Test flaskifying a response. """ resp = utils.flaskify(response.Response(message='value1')) assert resp.data == b'value1' assert resp.mimetype == 'text/plain' assert resp.status_code == 200 def test_flaskify_error_response(): """Flaskify an error response. """ resp = utils.flaskify(response.create_fatal_response('Fatal Error')) assert resp.status_code == 500 data = json.loads(resp.data.decode('utf8')) assert data == {'message': 'Fatal Error', 'code': 'internal_error'} @pytest.mark.parametrize('input_data, output', [ ('654321', '654321') ]) def test_get_orchard_user_id(input_data, output, feature_engine): """Test get_orchard_user_id function. Check the correct trimming of string """ header_mock = flexmock(get=lambda x, _: input_data) request_mock = flexmock(headers=header_mock) result = utils.get_orchard_user_id(request_mock) assert result == output VALID_RESPONSE_JSON = {'test': 1} VALID_RESPONSE_ERROR = 'Some error' def valid_response(): response = models.Response() response.status_code = 200 response._content = str.encode(json.dumps(VALID_RESPONSE_JSON)) return response def error_response(): response = models.Response() response.status_code = 400 response._content = str.encode(VALID_RESPONSE_ERROR) return response def invalid_response(): response = models.Response() response.status_code = 503 response._content = None return response @pytest.mark.parametrize('response, parsed_json', [ (valid_response(), VALID_RESPONSE_JSON), (error_response(), VALID_RESPONSE_ERROR), (invalid_response(), '') ]) def test_get_response_json(response, parsed_json): message = utils.get_response_json(response) assert parsed_json == message def initial_report_response(): return response.Response( message={ 'content': 'ISRC\r\nUSA12345678\r\nUSA9876543\r\n', 'file_name': '2017-03-24_Bulk_Update_UPCs_ISRC_123.csv'} ) def test_send_csv_file(): """Test send_csv_file helper function. """ with application.app.test_request_context(): correlation_id = '123456789' user_id = 987 result = utils.send_csv_file( initial_report_response(), correlation_id, user_id) assert result.status_code == 200 def test_retry_succeded(): """Test retry decorator successfull retry """ counter = {'count': 0} @utils.retry( error_condition=lambda err: type(err) is utils.OwsCarveoutError) def func_to_decorate(counter): counter['count'] += 1 if counter['count'] == 1: raise utils.OwsCarveoutError( status_code=504, message='Example message' ) else: return True result = func_to_decorate(counter) assert result assert counter['count'] == 2 def test_retry_count_exceeded(): """Test retry decorator raises RetryCountExceededError if retry limit exceeded """ @utils.retry( error_condition=lambda err: type(err) is utils.OwsCarveoutError, retry_count=1) def func_to_decorate(): raise utils.OwsCarveoutError( status_code=504, message='Example message' ) with pytest.raises(utils.RetryCountExceededError): func_to_decorate() @freeze_time('2017-11-01 15:00:00') def test_get_timestamp_for_dynamo(): """Expect correct time stamp as string.""" expected = Decimal(str(datetime.datetime.utcnow().timestamp())) result = utils.get_timestamp_for_dynamo() assert result == expected def test_load_json_from_request(): """Expect to load data correctly.""" context_headers = { 'Content-Type': 'application/json' } test_data = { 'hello': 'world' } with application.app.test_request_context( '/hello', headers=context_headers, data=json.dumps(test_data)): result = utils.load_json_from_request() assert result.message == test_data def test_load_json_from_request_no_content_type(): """Expect to load json even if Content-Type not set.""" test_data = { 'hello': 'world' } with application.app.test_request_context( '/hello', data=json.dumps(test_data)): result = utils.load_json_from_request() assert result.message == test_data def test_load_json_from_request_bad_json(): """Expect to handle corrupt payload.""" with application.app.test_request_context('/hello', data=b'{'): result = utils.load_json_from_request() assert result.status == 400 def test_load_json_from_request_no_json(): """Expect to handle absence of payload.""" with application.app.test_request_context('/hello'): result = utils.load_json_from_request() assert result.status == 400 def test_load_json_from_request_empty_payload(): """Expect to handle empty payload.""" with application.app.test_request_context('/hello', data=b'{}'): result = utils.load_json_from_request() assert result.status == 400 def test_get_orchard_user_id_removes_prefix(feature_engine): """Expect to remove any prefix(not only 'oa:') from orchard_user_id.""" test_user_id = '123' mock_request = Mock() mock_request.headers = {'Orchard-User-Id': test_user_id} result = utils.get_orchard_user_id(mock_request) assert result == test_user_id @pytest.mark.parametrize('prefix', ['oa:', 'alw:']) def test_get_orchard_user_id_auto_update_registry_claims_enabled(prefix): """Expect to return orchard_user_id with a prefix""" test_user_id = '{}123'.format(prefix) mock_request = Mock() mock_request.headers = {'Orchard-User-Id': test_user_id} result = utils.get_orchard_user_id(mock_request) assert result == test_user_id def test_get_orchard_user_id_empty_header(feature_engine): """Expect to handle case when Orchard-User-Id is empty string.""" mock_request = Mock() mock_request.headers = {'Orchard-User-Id': ''} result = utils.get_orchard_user_id(mock_request) assert result == '' def equal_dicts(source, target, ignore_keys=None): """Compare dicts but ignore some keys. It can be useful to compare dynamoDB items, ignoring timestamp values. Args: source (dict): First dict to compare target (dict): Second dict to compare ignore_keys (list): List of keys to ignore Returns: bool: equal dicts """ if not ignore_keys: ignore_keys = [] source_filtered = dict( (k, v) for k, v in source.items() if k not in ignore_keys) target_filtered = dict( (k, v) for k, v in target.items() if k not in ignore_keys) return source_filtered == target_filtered def report_to_list(report, separator='\n'): """Convert report to list where each row is dict. Keys in dict are headers of csv file. Args: report (str): generated csv report separator (str): what to use to split report Returns: list: report as list """ report = report.split(separator) reader = csv.DictReader(report) return list(reader)