From fb9436e2edf415eedd7a6a91e8ef4c41d71c91e5 Mon Sep 17 00:00:00 2001 From: Ivan Grebenshchikov Date: Wed, 20 Sep 2023 00:30:48 +0200 Subject: [PATCH] LITE-28562 Implement delegate_to_l2 task --- connect_ext_ppr/constants.py | 1 + connect_ext_ppr/models/task.py | 2 +- connect_ext_ppr/service.py | 6 +- connect_ext_ppr/tasks_manager.py | 87 ++++++++- connect_ext_ppr/utils.py | 24 +++ connect_ext_ppr/webapp.py | 4 +- tests/api/test_pprs.py | 21 +- tests/conftest.py | 38 ++-- tests/fixtures/test_PPR_file_delegate_l2.xlsx | Bin 0 -> 89231 bytes tests/test_tasks_manager.py | 179 ++++++++++++++++-- tests/test_utils.py | 6 + 11 files changed, 315 insertions(+), 53 deletions(-) create mode 100644 tests/fixtures/test_PPR_file_delegate_l2.xlsx diff --git a/connect_ext_ppr/constants.py b/connect_ext_ppr/constants.py index e7dcc14..cf6f80d 100644 --- a/connect_ext_ppr/constants.py +++ b/connect_ext_ppr/constants.py @@ -527,6 +527,7 @@ ], } PPR_FILE_NAME = "PPR_{product_id}_v{version}_{timestamp}.xlsx" +PPR_FILE_NAME_DELEGATION_L2 = "{dr_id}-L2Delegation-{ppr_id}-{timestamp}.xlsx" DESCRIPTION_TEMPLATE = """ **Description** {description} diff --git a/connect_ext_ppr/models/task.py b/connect_ext_ppr/models/task.py index 909b9cc..4b9935f 100644 --- a/connect_ext_ppr/models/task.py +++ b/connect_ext_ppr/models/task.py @@ -24,7 +24,7 @@ class Task(Model): ) deployment_request_id = db.Column(db.ForeignKey(DeploymentRequest.id)) title = db.Column(db.String(100)) - error_message = db.Column(db.String((4000))) + error_message = db.Column(db.String(4000)) type = db.Column(db.Enum(TaskTypesChoices, validate_strings=True)) created_at = db.Column(db.DateTime(), default=datetime.utcnow) diff --git a/connect_ext_ppr/service.py b/connect_ext_ppr/service.py index 215a69b..d7a0307 100644 --- a/connect_ext_ppr/service.py +++ b/connect_ext_ppr/service.py @@ -1,4 +1,3 @@ -import os from datetime import datetime import pandas as pd @@ -25,6 +24,7 @@ create_ppr_to_media, get_base_workbook, get_configuration_from_media, + get_file_size, get_ppr_from_media, get_product_items, get_user_data_from_auth_token, @@ -238,9 +238,7 @@ def create_ppr(ppr, user_id, deployment, db, client, logger): file_obj = open(file.name, 'rb') writer.book.save(file_obj.name) - file_obj.seek(0, os.SEEK_END) - file_size = file_obj.tell() - file_obj.seek(0) + file_size = get_file_size(file_obj) file_name = PPR_FILE_NAME.format( product_id=deployment.product_id, version=new_version, diff --git a/connect_ext_ppr/tasks_manager.py b/connect_ext_ppr/tasks_manager.py index 714d688..ff9424f 100644 --- a/connect_ext_ppr/tasks_manager.py +++ b/connect_ext_ppr/tasks_manager.py @@ -5,6 +5,7 @@ from sqlalchemy.orm import joinedload, selectinload from connect_ext_ppr.client.exception import ClientError +from connect_ext_ppr.constants import PPR_FILE_NAME_DELEGATION_L2 from connect_ext_ppr.db import get_cbc_extension_db, get_db_ctx_manager from connect_ext_ppr.models.enums import CBCTaskLogStatus from connect_ext_ppr.models.enums import ( @@ -18,6 +19,13 @@ from connect_ext_ppr.models.task import Task from connect_ext_ppr.services.cbc_extension import get_hub_credentials from connect_ext_ppr.services.cbc_hub import CBCService +from connect_ext_ppr.utils import ( + create_dr_file_to_media, + get_base_workbook, + get_file_size, + get_ppr_from_media, + process_ppr_file_for_delelegate_l2, +) class TaskException(Exception): @@ -82,6 +90,51 @@ def _check_cbc_task_status(cbc_service, tracking_id): raise TaskException(f'Something went wrong with task: {tracking_id}') +def prepare_ppr_file_for_task( + connect_client, + file_data, + file_name_template, + deployment_request, + deployment, + process_func, +): + file, writer, wb = get_base_workbook(file_data) + + try: + ws_list = [] + for sheet_name in wb.sheet_names: + ws = wb.parse(sheet_name) + process_func(sheet_name, ws) + ws.name = sheet_name + ws_list.append(ws) + + for ws in ws_list: + ws.to_excel(writer, ws.name, index=False) + file_obj = open(file.name, 'rb') + writer.book.save(file_obj.name) + + file_size = get_file_size(file_obj) + file_name = file_name_template.format( + dr_id=deployment_request.id, + ppr_id=deployment_request.ppr.id, + timestamp=datetime.utcnow().strftime("%s"), + ) + create_dr_file_to_media( + connect_client, + deployment.account_id, + deployment_request.id, + file_name, + file_obj.read(), + file_size, + ) + + file_obj.seek(0) + return file_obj + + except (FileNotFoundError, ValueError, KeyError) as e: + raise TaskException(f'Error while processing PPR file: {e}') + + def validate_ppr(deployment_request, **kwargs): return True @@ -113,8 +166,31 @@ def apply_ppr_and_delegate_to_marketplaces(deployment_request, **kwargs): return True -def delegate_to_l2(deployment_request, **kwargs): - return True +def delegate_to_l2(deployment_request, cbc_service, connect_client, **kwargs): + if deployment_request.manually: + return True + + ppr_file_id = deployment_request.ppr.file + deployment = deployment_request.deployment + file_data = get_ppr_from_media( + connect_client, + deployment.account_id, + deployment.id, + ppr_file_id, + ) + + file = prepare_ppr_file_for_task( + connect_client=connect_client, + file_data=file_data, + file_name_template=PPR_FILE_NAME_DELEGATION_L2, + deployment_request=deployment_request, + deployment=deployment, + process_func=process_ppr_file_for_delelegate_l2, + ) + + tracking_id = _send_ppr(cbc_service, file) + file.close() + return _check_cbc_task_status(cbc_service, tracking_id) TASK_PER_TYPE = { @@ -124,7 +200,7 @@ def delegate_to_l2(deployment_request, **kwargs): } -def execute_tasks(db, config, tasks): +def execute_tasks(db, config, tasks, connect_client): was_succesfull = False cbc_service = _get_cbc_service(config, tasks[0].deployment_request.deployment) @@ -140,6 +216,7 @@ def execute_tasks(db, config, tasks): was_succesfull = TASK_PER_TYPE.get(task.type)( deployment_request=task.deployment_request, cbc_service=cbc_service, + connect_client=connect_client, ) task.status = TasksStatusChoices.done if not was_succesfull: @@ -162,7 +239,7 @@ def execute_tasks(db, config, tasks): return was_succesfull -def main_process(deployment_request_id, config): +def main_process(deployment_request_id, config, connect_client): with get_db_ctx_manager(config) as db: deployment_request = db.query(DeploymentRequest).options( @@ -187,7 +264,7 @@ def main_process(deployment_request_id, config): deployment_request_id=deployment_request_id, ).order_by(Task.id).all() - was_succesfull = execute_tasks(db, config, tasks) + was_succesfull = execute_tasks(db, config, tasks, connect_client) db.refresh(deployment_request, with_for_update=True) diff --git a/connect_ext_ppr/utils.py b/connect_ext_ppr/utils.py index 4bd0206..de6bd04 100644 --- a/connect_ext_ppr/utils.py +++ b/connect_ext_ppr/utils.py @@ -142,6 +142,16 @@ def create_ppr_to_media(client, account_id, deployment_id, filename, content, fi return json.loads(media_file) +def create_dr_file_to_media(client, account_id, dr_id, filename, content, file_size=None): + file_collection = FileCollection.PPR + file_type = MimeTypeChoices.application_vnd_ms_xslx + media_file = create_media_file( + client, account_id, dr_id, file_collection, + filename, content, file_type, file_size, + ) + return json.loads(media_file) + + @connect_error def get_file_from_media(client, account_id, deployment_id, media_id, file_collection): return namespaced_media_client( @@ -636,3 +646,17 @@ def _build_summary(summary: dict, indent: int = 0): def build_summary(summary: dict): return SUMMARY_TEMPLATE.format(summary=_build_summary(summary)) + + +def get_file_size(file_obj): + file_obj.seek(0, os.SEEK_END) + file_size = file_obj.tell() + file_obj.seek(0) + return file_size + + +def process_ppr_file_for_delelegate_l2(sheet_name, ws): + if sheet_name == 'OpUnitServicePlans': + ws['Published'] = 'TRUE' + elif sheet_name == 'ServicePlans': + ws['Published'] = 'FALSE' diff --git a/connect_ext_ppr/webapp.py b/connect_ext_ppr/webapp.py index bf81ab9..51a13af 100644 --- a/connect_ext_ppr/webapp.py +++ b/connect_ext_ppr/webapp.py @@ -177,7 +177,7 @@ def add_dep_request( db, deployment_request, deployment, account_id, logger, ) - self.thread_pool.submit(main_process, instance.id, config) + self.thread_pool.submit(main_process, instance.id, config, client) hub = get_client_object(client, 'hubs', instance.deployment.hub_id) response = get_deployment_request_schema(instance, hub) @@ -355,7 +355,7 @@ def retry( dr = get_deployment_request_by_id(depl_req_id, db, installation) dr = DeploymentRequestActionHandler.retry(db, dr) - self.thread_pool.submit(main_process, dr.id, config) + self.thread_pool.submit(main_process, dr.id, config, client) hub = get_hub(client, dr.deployment.hub_id) return get_deployment_request_schema(dr, hub) diff --git a/tests/api/test_pprs.py b/tests/api/test_pprs.py index 5dd8ff0..a7df711 100644 --- a/tests/api/test_pprs.py +++ b/tests/api/test_pprs.py @@ -1,5 +1,4 @@ import json -import os import pytest @@ -278,9 +277,7 @@ def test_upload_ppr( ): deployment = deployment_factory() - current_dir = os.path.dirname(os.path.abspath(__file__)) - file_path = os.path.join(current_dir, '..', 'fixtures', 'test_PPR_file.xlsx') - with open(file_path, 'rb') as f: + with open('./tests/fixtures/test_PPR_file.xlsx', 'rb') as f: binary_data = f.read() mocker.patch( 'connect_ext_ppr.service.get_ppr_from_media', @@ -340,9 +337,7 @@ def test_upload_ppr_invalid( ): deployment = deployment_factory() - current_dir = os.path.dirname(os.path.abspath(__file__)) - file_path = os.path.join(current_dir, '..', 'fixtures', 'test_PPR_file_invalid.xlsx') - with open(file_path, 'rb') as f: + with open('./tests/fixtures/test_PPR_file_invalid.xlsx', 'rb') as f: binary_data = f.read() mocker.patch( 'connect_ext_ppr.service.get_ppr_from_media', @@ -408,9 +403,7 @@ def test_post_ppr_new_version( assert dbsession.query(PPRVersion).count() == 1 assert dbsession.query(File).count() == 1 - current_dir = os.path.dirname(os.path.abspath(__file__)) - file_path = os.path.join(current_dir, '..', 'fixtures', 'test_PPR_file.xlsx') - with open(file_path, 'rb') as f: + with open('./tests/fixtures/test_PPR_file.xlsx', 'rb') as f: binary_data = f.read() mocker.patch( 'connect_ext_ppr.service.get_ppr_from_media', @@ -500,9 +493,7 @@ def test_post_ppr_file_already_exists( file = file_factory( mime_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', ) - current_dir = os.path.dirname(os.path.abspath(__file__)) - file_path = os.path.join(current_dir, '..', 'fixtures', 'test_PPR_file.xlsx') - with open(file_path, 'rb') as f: + with open('./tests/fixtures/test_PPR_file.xlsx', 'rb') as f: binary_data = f.read() mocker.patch( 'connect_ext_ppr.service.get_ppr_from_media', @@ -545,9 +536,7 @@ def test_generate_ppr( deployment = deployment_factory(product_id='PRD-XXX-XXX-XXX') configuration = configuration_factory(deployment=deployment.id) - current_dir = os.path.dirname(os.path.abspath(__file__)) - file_path = os.path.join(current_dir, '..', 'fixtures', 'configuration.json') - with open(file_path, 'rb') as f: + with open('./tests/fixtures/configuration.json', 'rb') as f: conf_data = json.load(f) mocker.patch( 'connect_ext_ppr.service.get_configuration_from_media', diff --git a/tests/conftest.py b/tests/conftest.py index 9cfe296..8203b6b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -29,6 +29,7 @@ DeploymentRequest, MarketplaceConfiguration, ) +from connect_ext_ppr.models.enums import TaskTypesChoices from connect_ext_ppr.models.file import File from connect_ext_ppr.models.ppr import PPRVersion from connect_ext_ppr.models.replicas import Account, Product @@ -145,12 +146,12 @@ def deployment(dbsession, product_factory): @pytest.fixture def deployment_factory(dbsession, product_factory): def _build_deployment( - id=None, - product_id=None, - account_id='PA-000-000', - vendor_id='VA-000-000', - hub_id='HB-0000-0000', - status='pending', + id=None, + product_id=None, + account_id='PA-000-000', + vendor_id='VA-000-000', + hub_id='HB-0000-0000', + status='pending', ): product = product_factory(id=product_id, owner_id=vendor_id) product_id = product.id @@ -172,13 +173,13 @@ def _build_deployment( @pytest.fixture def deployment_request_factory(dbsession, deployment_factory): def _build_deployment_request( - deployment=None, - ppr=None, - delegate_l2=False, - status=None, - started_at=None, - finished_at=None, - manually=False, + deployment=None, + ppr=None, + delegate_l2=False, + status=None, + started_at=None, + finished_at=None, + manually=False, ): if not deployment: deployment = deployment_factory() @@ -1145,3 +1146,14 @@ def connect_auth_header(): def configuration_json(): with open('./tests/fixtures/configuration.json') as json_file: return json.load(json_file) + + +@pytest.fixture +def mock_tasks(mocker): + mocker.patch( + 'connect_ext_ppr.tasks_manager.TASK_PER_TYPE', return_value={ + TaskTypesChoices.ppr_validation: lambda: True, + TaskTypesChoices.apply_and_delegate: lambda: True, + TaskTypesChoices.delegate_to_l2: lambda: True, + }, + ) diff --git a/tests/fixtures/test_PPR_file_delegate_l2.xlsx b/tests/fixtures/test_PPR_file_delegate_l2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7dc33286c63cafb97e498f51f4a72cd892e985b8 GIT binary patch literal 89231 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 MAl2OhwFBXQ0o?Apg8%>k literal 0 HcmV?d00001 diff --git a/tests/test_tasks_manager.py b/tests/test_tasks_manager.py index 05e2b8d..782c2b8 100644 --- a/tests/test_tasks_manager.py +++ b/tests/test_tasks_manager.py @@ -1,4 +1,5 @@ import copy +from io import BufferedReader import pytest @@ -28,15 +29,13 @@ ) from connect_ext_ppr.services.cbc_hub import CBCService +from tests.test_utils import check_excel_file_column_values + def test_apply_ppr_and_delegate_to_marketplaces(deployment_request_factory): assert apply_ppr_and_delegate_to_marketplaces(deployment_request_factory()) -def test_delegate_to_l2(deployment_request_factory): - assert delegate_to_l2(deployment_request_factory()) - - def test_validate_ppr(deployment_request_factory): assert validate_ppr(deployment_request_factory()) @@ -191,6 +190,148 @@ def test_check_and_update_product_w_errors_in_update_product( ) +@patch.object(CBCService, '__init__') +def test_delegate_to_l2( + mock___init__, + connect_client, + product_details, + update_product_response, + deployment_request_factory, + mocker, +): + mock___init__.return_value = None + cbc_sevice = CBCService() + ppr_file_data = open('./tests/fixtures/test_PPR_file_delegate_l2.xlsx', 'rb').read() + assert not check_excel_file_column_values( + ppr_file_data, 'OpUnitServicePlans', 'Published', True, + ) + assert not check_excel_file_column_values(ppr_file_data, 'ServicePlans', 'Published', False) + + file_sent = null + + def send_ppr_side_effect(*args): + nonlocal file_sent + file_sent = args[1].read() + + send_ppr_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager._send_ppr', + return_value=101, + side_effect=send_ppr_side_effect, + ) + + get_from_media_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager.get_ppr_from_media', + return_value=ppr_file_data, + ) + create_dr_file_to_media_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager.create_dr_file_to_media', + ) + check_cbc_task_status_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager._check_cbc_task_status', + ) + + assert delegate_to_l2( + deployment_request=deployment_request_factory(), + cbc_service=cbc_sevice, + connect_client=connect_client, + ) + + assert get_from_media_mock.call_count == 1 + assert create_dr_file_to_media_mock.call_count == 1 + assert send_ppr_mock.call_count == 1 + assert check_cbc_task_status_mock.call_count == 1 + + assert send_ppr_mock.call_args.args[0] == cbc_sevice + ppr_file_arg = send_ppr_mock.call_args.args[1] + assert isinstance(ppr_file_arg, BufferedReader) + assert check_excel_file_column_values(file_sent, 'OpUnitServicePlans', 'Published', True) + assert check_excel_file_column_values(file_sent, 'ServicePlans', 'Published', False) + + +@patch.object(CBCService, '__init__') +def test_delegate_to_l2_manually( + mock___init__, + connect_client, + product_details, + update_product_response, + deployment_request_factory, + mocker, +): + mock___init__.return_value = None + cbc_sevice = CBCService() + + send_ppr_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager._send_ppr', + ) + get_from_media_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager.get_ppr_from_media', + ) + create_dr_file_to_media_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager.create_dr_file_to_media', + ) + check_cbc_task_status_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager._check_cbc_task_status', + ) + + assert delegate_to_l2( + deployment_request=deployment_request_factory(manually=True), + cbc_service=cbc_sevice, + connect_client=connect_client, + ) + + assert get_from_media_mock.call_count == 0 + assert create_dr_file_to_media_mock.call_count == 0 + assert send_ppr_mock.call_count == 0 + assert check_cbc_task_status_mock.call_count == 0 + + +@patch.object(CBCService, '__init__') +def test_delegate_to_l2_processing_error( + mock___init__, + connect_client, + product_details, + update_product_response, + deployment_request_factory, + mocker, +): + mock___init__.return_value = None + cbc_sevice = CBCService() + ppr_file_data = open('./tests/fixtures/test_PPR_file_delegate_l2.xlsx', 'rb').read() + + send_ppr_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager._send_ppr', + return_value=101, + ) + get_from_media_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager.get_ppr_from_media', + return_value=ppr_file_data, + ) + process_ppr_file_for_delelegate_l2_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager.process_ppr_file_for_delelegate_l2', + side_effect=ValueError('Wrong value "Cthulhu"'), + ) + create_dr_file_to_media_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager.create_dr_file_to_media', + ) + check_cbc_task_status_mock = mocker.patch( + 'connect_ext_ppr.tasks_manager._check_cbc_task_status', + ) + + with pytest.raises(TaskException) as e: + delegate_to_l2( + deployment_request=deployment_request_factory(), + cbc_service=cbc_sevice, + connect_client=connect_client, + ) + assert str(e.value) == 'Error while processing PPR file: Wrong value "Cthulhu"' + + assert get_from_media_mock.call_count == 1 + assert process_ppr_file_for_delelegate_l2_mock.call_count == 1 + assert create_dr_file_to_media_mock.call_count == 0 + assert send_ppr_mock.call_count == 0 + assert check_cbc_task_status_mock.call_count == 0 + + @patch.object(CBCService, '__init__', return_value=None) def test_main_process( mock___init__, @@ -199,6 +340,8 @@ def test_main_process( deployment_request_factory, task_factory, ppr_version_factory, + connect_client, + mock_tasks, mocker, ): dep = deployment_factory() @@ -211,7 +354,7 @@ def test_main_process( with mocker.patch( 'connect_ext_ppr.tasks_manager._get_cbc_service', return_value=CBCService(), ): - assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.done + assert main_process(dr.id, {}, connect_client) == DeploymentRequestStatusChoices.done assert dbsession.query(Deployment).filter_by(status=DeploymentStatusChoices.synced).count() == 1 assert dbsession.query(DeploymentRequest).filter_by( @@ -232,6 +375,8 @@ def test_main_process_wo_l2_delegation( deployment_request_factory, task_factory, ppr_version_factory, + connect_client, + mock_tasks, mocker, ): dep = deployment_factory() @@ -241,7 +386,7 @@ def test_main_process_wo_l2_delegation( task_factory(deployment_request=dr, task_index='0002', type=TaskTypesChoices.apply_and_delegate) mocker.patch('connect_ext_ppr.tasks_manager._get_cbc_service', return_value=CBCService()) - assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.done + assert main_process(dr.id, {}, connect_client) == DeploymentRequestStatusChoices.done assert dbsession.query(Deployment).filter_by( status=DeploymentStatusChoices.pending, @@ -265,6 +410,8 @@ def test_main_process_deployment_w_new_ppr_version( deployment_request_factory, task_factory, ppr_version_factory, + connect_client, + mock_tasks, mocker, ): ppr_file = file_factory(id='MFL-123') @@ -278,7 +425,7 @@ def test_main_process_deployment_w_new_ppr_version( task_factory(deployment_request=dr, task_index='0003', type=TaskTypesChoices.delegate_to_l2) mocker.patch('connect_ext_ppr.tasks_manager._get_cbc_service', return_value=CBCService()) - assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.done + assert main_process(dr.id, {}, connect_client) == DeploymentRequestStatusChoices.done assert dbsession.query(Deployment).filter_by( status=DeploymentStatusChoices.pending, @@ -314,6 +461,8 @@ def test_main_process_ends_w_error( mocker, task_factory, ppr_version_factory, + connect_client, + mock_tasks, ): dep = deployment_factory() ppr = ppr_version_factory(id='PPR-123', product_version=1, deployment=dep, version=1) @@ -325,13 +474,13 @@ def test_main_process_ends_w_error( my_mock = mocker.Mock() def mock_get(key): - print(type_function_to_mock) return lambda **kwargs: key != type_function_to_mock + my_mock.get = mock_get mocker.patch('connect_ext_ppr.tasks_manager._get_cbc_service', return_value=CBCService()) mocker.patch('connect_ext_ppr.tasks_manager.TASK_PER_TYPE', my_mock) - assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.error + assert main_process(dr.id, {}, connect_client) == DeploymentRequestStatusChoices.error assert dbsession.query(Deployment).filter_by( status=DeploymentStatusChoices.pending, @@ -388,6 +537,8 @@ def test_main_process_w_aborted_tasks( task_statuses, done_tasks, aborted_tasks, + connect_client, + mock_tasks, mocker, ): """ @@ -430,7 +581,7 @@ def change_dr_status(instance, attribute_names=None, with_for_update=None): dbsession.refresh = change_dr_status mocker.patch('connect_ext_ppr.tasks_manager._get_cbc_service', return_value=CBCService()) - assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.aborted + assert main_process(dr.id, {}, connect_client) == DeploymentRequestStatusChoices.aborted assert dbsession.query(Deployment).filter_by( status=DeploymentStatusChoices.pending, @@ -455,6 +606,8 @@ def test_main_process_w_aborted_deployment_request( deployment_request_factory, task_factory, ppr_version_factory, + connect_client, + mock_tasks, ): """ We only process DeploymentRequest that are in Pending status. So in this case we asume that @@ -488,7 +641,7 @@ def test_main_process_w_aborted_deployment_request( status=TasksStatusChoices.aborted, ) - assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.aborted + assert main_process(dr.id, {}, connect_client) == DeploymentRequestStatusChoices.aborted assert dbsession.query(Deployment).filter_by( status=DeploymentStatusChoices.pending, @@ -523,6 +676,8 @@ def test_main_process_ends_w_task_exception( mocker, task_factory, ppr_version_factory, + connect_client, + mock_tasks, ): dep = deployment_factory() ppr = ppr_version_factory(id='PPR-123', product_version=1, deployment=dep, version=1) @@ -542,7 +697,7 @@ def mock_get(key): mocker.patch('connect_ext_ppr.tasks_manager.TASK_PER_TYPE', my_mock) mocker.patch('connect_ext_ppr.tasks_manager._get_cbc_service', return_value=CBCService()) - assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.error + assert main_process(dr.id, {}, connect_client) == DeploymentRequestStatusChoices.error assert dbsession.query(Deployment).filter_by( status=DeploymentStatusChoices.pending, diff --git a/tests/test_utils.py b/tests/test_utils.py index 416a1ed..71c6e0c 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -450,3 +450,9 @@ def test_get_all_info_w_marketplace_not_available( assert get_all_listing_info(connect_client, status='unlisted') == [] assert get_all_listing_info(connect_client) == [] + + +def check_excel_file_column_values(file, sheet_name, column_name, value): + wb = pd.ExcelFile(file) + ws1 = wb.parse(sheet_name) + return (ws1[column_name] == value).all()