Skip to content

Commit

Permalink
Merge pull request #26 from cloudblue/LITE-29330-user-can-force-uploa…
Browse files Browse the repository at this point in the history
…d-from-feed

LITE-29330 User can force upload from Feed
  • Loading branch information
jonatrios authored Feb 14, 2024
2 parents 959e5e1 + 519a244 commit 1d2cc48
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 0 deletions.
25 changes: 25 additions & 0 deletions connect_bi_reporter/uploads/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from connect_bi_reporter.scheduler import Scheduler
from connect_bi_reporter.uploads.api.schemas import map_to_upload_schema, UploadSchema
from connect_bi_reporter.uploads.services import (
force_upload,
get_feed_for_uploads,
get_upload_or_404,
get_uploads_or_404,
retry_failed_upload,
Expand Down Expand Up @@ -71,3 +73,26 @@ def get_retry_upload(
scheduler = Scheduler(client, context, logger)
upload = retry_failed_upload(db, installation, feed_id, upload_id, scheduler)
return map_to_upload_schema(upload)

def _force_upload(self, db, client, context, logger, installation, feed):
scheduler = Scheduler(client, context, logger)
upload = force_upload(db, client, scheduler, installation, feed)
return map_to_upload_schema(upload)

@router.post(
'/feeds/{feed_id}/uploads/force',
summary='Force creation of Upload from a Feed',
response_model=UploadSchema,
status_code=status.HTTP_201_CREATED,
)
def force_upload(
self,
feed_id: str,
db: VerboseBaseSession = Depends(get_db),
client: ConnectClient = Depends(get_installation_client),
context: Context = Depends(get_call_context),
logger: Logger = Depends(get_logger),
installation: dict = Depends(get_installation),
):
feed = get_feed_for_uploads(db, installation, feed_id)
return self._force_upload(db, client, context, logger, installation, feed)
2 changes: 2 additions & 0 deletions connect_bi_reporter/uploads/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ class UploadError(ExtensionErrorBase):

ERRORS = {
0: "Can not retry Upload `{upload_id}`: {reason}",
1: "Can not force Upload creation for Feed `{feed_id}` in status `{status}`.",
2: "Error while forcing Upload for Feed `{feed_id}`: {reason}",
}
35 changes: 35 additions & 0 deletions connect_bi_reporter/uploads/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,38 @@ def retry_failed_upload(
upload.status = Upload.STATUSES.pending
db.commit()
return upload


def force_upload(db, client, scheduler, installation, feed):
if feed.status == FeedStatusChoices.disabled:
raise UploadError.UPL_001(
format_kwargs={
'feed_id': feed.id,
'status': feed.status,
},
)
logger = scheduler.logger
try:
uploads = create_uploads(db, client, logger, [feed])
create_process_upload_tasks(
uploads,
scheduler,
installation_id=installation['id'],
account_id=installation['owner']['id'],
)
except ClientError:
reason = Errors.connect_client_error
logger.exception(reason)
raise UploadError.UPL_002(
format_kwargs={
'feed_id': feed.id,
'reason': reason,
})
if not uploads:
reason = 'Validation error.'
raise UploadError.UPL_002(
format_kwargs={
'feed_id': feed.id,
'reason': reason,
})
return uploads[0]
186 changes: 186 additions & 0 deletions tests/uploads/api/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,189 @@ def test_retry_upload_fail_client_error(
f'Connect client Error.'
)
assert upload.status == 'failed'


def test_feed_force_upload(
installation,
feed_factory,
upload_factory,
api_client,
connect_auth_header,
mocker,
):
feed = feed_factory(account_id=installation['owner']['id'])
upload = upload_factory(feed_id=feed.id, name='name')

mocker.patch(
'connect_bi_reporter.uploads.services.create_uploads',
return_value=[upload],
)
mocker.patch(
'connect_bi_reporter.uploads.services.create_process_upload_tasks',
return_value=None,
)

response = api_client.post(
f'/api/feeds/{feed.id}/uploads/force',
installation=installation,
headers={'connect-auth': connect_auth_header},
)

assert response.status_code == 201

response_data = response.json()
assert response_data['id'] == upload.id
assert response_data['id'].startswith(upload_factory._meta.model.PREFIX)
assert response_data['name'] == upload.name
events = response_data['events']
assert events['created']['at'] is not None
assert events['updated']['at'] is not None
assert response_data['status'] == 'pending'


def test_feed_force_upload_fail_feed_disable(
installation,
feed_factory,
api_client,
connect_auth_header,
):
feed = feed_factory(account_id=installation['owner']['id'], status='disabled')

response = api_client.post(
f'/api/feeds/{feed.id}/uploads/force',
installation=installation,
headers={'connect-auth': connect_auth_header},
)

assert response.status_code == 400

response_data = response.json()
assert response_data['error_code'] == 'UPL_001'
assert response_data['errors'][0] == (
f'Can not force Upload creation for '
f'Feed `{feed.id}` in status `{feed.status}`.'
)


@pytest.mark.parametrize(
'report_file,rs,message,report_id',
(
(
{'id': 'RP-262-019-481', 'renderer': 'csv'},
{'return_value': {'id': 'RS-001', 'status': 'disabled'}},
(
"Skipping Upload creation for Report Schedule `RS-2796-9021`: "
"'Report Schedule `RS-2796-9021` invalid status `disabled`'."
),
'foo',
),
(
{'id': 'RP-262-019-481', 'renderer': 'excel'},
{'return_value': {'id': 'RS-001', 'status': 'enabled'}},
(
"Skipping Upload creation for Report Schedule `RS-2796-9021`: "
"'Report File `RP-262-019-481` renderer `excel` not allowed'."
),
'foo',
),
(
{'id': 'RP-262-019-481', 'renderer': 'excel'},
{'side_effect': ClientError(status_code=500)},
(
"Skipping Upload creation for Report Schedule `RS-2796-9021`: "
"'Report Schedule `RS-2796-9021` can not be found (500 Internal Server Error)'."
),
'foo',
),
(
{'id': 'RP-262-019-481', 'renderer': 'csv'},
{'return_value': {'id': 'RS-001', 'status': 'enabled'}},
(
"Skipping Upload creation for Report Schedule `RS-2796-9021`: "
"'Report File `RP-262-019-481` is already related to an existing Upload'."
),
'RP-262-019-481',
),
),
)
def test_feed_force_upload_fail_validation_error(
installation,
report_schedule,
feed_factory,
upload_factory,
mocker,
report_file,
rs,
message,
report_id,
api_client,
connect_auth_header,
caplog,
):
feed = feed_factory(
schedule_id=report_schedule['id'],
account_id=installation['owner']['id'],
status=feed_factory._meta.model.STATUSES.enabled,
)
upload_factory(
feed_id=feed.id,
report_id=report_id,
)

mocker.patch(
'connect_bi_reporter.uploads.services.get_report_schedule',
**rs,
)
mocker.patch(
'connect_bi_reporter.uploads.services.get_reporting_report',
return_value=report_file,
)
response = api_client.post(
f'/api/feeds/{feed.id}/uploads/force',
installation=installation,
headers={'connect-auth': connect_auth_header},
)

assert response.status_code == 400

response_data = response.json()
assert response_data['error_code'] == 'UPL_002'
assert response_data['errors'][0] == (
f'Error while forcing Upload for Feed `{feed.id}`: Validation error.'
)
assert caplog.records[0].message == message


def test_feed_force_upload_fail_client_error(
installation,
feed_factory,
upload_factory,
api_client,
connect_auth_header,
mocker,
):
feed = feed_factory(account_id=installation['owner']['id'])
upload = upload_factory(feed_id=feed.id, name='name')

mocker.patch(
'connect_bi_reporter.uploads.services.create_uploads',
return_value=[upload],
)
mocker.patch(
'connect_bi_reporter.uploads.services.create_process_upload_tasks',
side_effect=ClientError(message='Bad', status_code=500),
)

response = api_client.post(
f'/api/feeds/{feed.id}/uploads/force',
installation=installation,
headers={'connect-auth': connect_auth_header},
)

assert response.status_code == 400

response_data = response.json()
assert response_data['error_code'] == 'UPL_002'
assert response_data['errors'][0] == (
f'Error while forcing Upload for Feed `{feed.id}`: Connect client Error.'
)

0 comments on commit 1d2cc48

Please sign in to comment.