"""Tests for label copy export history model.""" from datetime import datetime from flexmock import flexmock from oto import response as oto_response from oto import status import pytest from sqlalchemy import exc from label_copy_export.connectors import mysql from label_copy_export.connectors import sentry from label_copy_export.constants import error from label_copy_export.constants import lce_history from label_copy_export.models import history @pytest.fixture def job_data(): """Dictionary with data suitable to create Job object.""" return { 'status': lce_history.GENERATION_STATUSES[0], 'user_id': 'oa:1234', 'project_id': 8765432, } def test_job_to_dict(test_database, job_data): """Assert Job object can convert itself to dict.""" job_obj = history.Job(**job_data) with mysql.label_copy_export_history_session_scope() as session: session.add(job_obj) session.commit() job_obj = session.query(history.Job).first() job_data['job_id'] = 1 job_data['last_change_date'] = job_obj.last_change_date assert job_obj.to_dict() == job_data def test_manual_job_last_change_date_raises_exc(test_database, job_data): """Assert can not change Job.last_change_date directly.""" job_obj = history.Job(**job_data) with mysql.label_copy_export_history_session_scope() as session: session.add(job_obj) job_obj = session.query(history.Job).first() initial_change_date = job_obj.last_change_date manual_change_date = datetime.utcnow() with pytest.raises(AttributeError): job_obj.last_change_date = manual_change_date session.commit() job_obj = session.query(history.Job).first() assert initial_change_date < manual_change_date assert initial_change_date == job_obj.last_change_date def test_change_status_of_job(test_database, job_data): """Assert can change Job status.""" job_obj = history.Job(**job_data) with mysql.label_copy_export_history_session_scope() as session: session.add(job_obj) job_obj = session.query(history.Job).first() creation_date = job_obj.last_change_date session.commit() response = history.change_status(job_obj.job_id, lce_history.COMPLETED) after_update_date = datetime.utcnow() job_obj = session.query(history.Job).first() assert job_obj.status == lce_history.COMPLETED assert creation_date < job_obj.last_change_date < after_update_date assert isinstance(response, oto_response.Response) assert response.status == status.NO_CONTENT def test_change_status_handles_not_found_job(test_database): """Assert change_status can properly respond when job not found.""" invalid_job_id = 111 response = history.change_status(invalid_job_id, lce_history.COMPLETED) assert response.status == 404 assert response.errors['message'] == error.JOB_DOES_NOT_EXIST @pytest.mark.parametrize('sentry_client', [None, flexmock()]) def test_change_status_handles_sqlalchemy_error(sentry_client): """Assert change_status handles SQLAlchemyError.""" expected_exception = exc.SQLAlchemyError('critical error') (flexmock(mysql) .should_receive('label_copy_export_history_session_scope') .and_raise(expected_exception)) (flexmock(sentry) .should_receive('sentry_client') .and_return(sentry_client)) if sentry_client: (flexmock(sentry.sentry_client) .should_receive('captureException') .once()) response = history.change_status(1, lce_history.COMPLETED) assert isinstance(response, oto_response.Response) assert response.errors['message'] == str(expected_exception) def test_change_status_of_job_when_multiple_products_exist( test_database, job_data): """Assert only latest job entry changed for given product_in_store.""" first_job = history.Job(**job_data) second_job = history.Job(**job_data) with mysql.label_copy_export_history_session_scope() as session: session.add(first_job) session.add(second_job) session.commit() history.change_status( second_job.job_id, lce_history.COMPLETED) first_job = session.query(history.Job).filter_by( job_id=first_job.job_id).first() assert first_job.status == job_data['status'] second_job = session.query(history.Job).filter_by( job_id=second_job.job_id).first() assert second_job.status == lce_history.COMPLETED