"""Functional tests for the POST /product/{product_id}/correction endpoint.""" import json from unittest import mock from flexmock import flexmock from owsrequest import request import pytest from product_digital.constants import header as header_constants from product_digital.constants import services from tests.factories import release as release_factory from tests.testutils import db @pytest.fixture def correction_data(): """Return a correction dict to submit in POST payloads.""" return { 'last_updated_by': 123, 'last_updated_type': 'oa' } @pytest.fixture def product_id(): """Return a fake product id for testing.""" return 12345 @pytest.fixture def post_correction_ok_response(product_id): """Return a fake OK response from workflow to stub posting a correction.""" post_response = mock.MagicMock(status_code=201) post_response.json = mock.MagicMock(return_value={ 'release_correction_id': 153129, 'status': 'active', 'release_id': product_id }) return post_response @db.test_schema def test_post_product_correction_success( client, correction_data, post_correction_ok_response, product_id, valid_headers): """Test status code upon successfully create a correction.""" existing_release = release_factory.ReleaseFactory.build( release_id=product_id) db.seed_models(existing_release) last_correction_response = mock.Mock(status_code=404) (flexmock(request).should_receive('get').with_args( services.OWS_PRODUCT_WORKFLOW, '/product/{}/correction'.format(product_id), ).and_return(last_correction_response)) (flexmock(request).should_receive('post').with_args( services.OWS_PRODUCT_WORKFLOW, '/product/{}/correction'.format(product_id), json=correction_data).and_return(post_correction_ok_response)) post_response = client.post( '/product/{}/correction'.format(product_id), headers=valid_headers, data=json.dumps(correction_data)) post_response_body = json.loads(post_response.data.decode()) assert post_response.status_code == 201 assert post_response_body == post_correction_ok_response.json() @db.test_schema def test_post_product_correction_vendor_updated_by( client, post_correction_ok_response, product_id, valid_headers): """Test that alw Orchard-User-Id populates last_updated as vendor.""" valid_headers[header_constants.ORCHARD_USER_ID] = 'alw:123' existing_release = release_factory.ReleaseFactory.build( release_id=product_id) db.seed_models(existing_release) last_correction_response = mock.Mock(status_code=404) (flexmock(request).should_receive('get').with_args( services.OWS_PRODUCT_WORKFLOW, '/product/{}/correction'.format(product_id), ).and_return(last_correction_response)) expected_correction_payload = { 'last_updated_by': 123, 'last_updated_type': 'vendor' } submitted_correction_payload = {} (flexmock(request).should_receive('post').with_args( services.OWS_PRODUCT_WORKFLOW, '/product/{}/correction'.format(product_id), json=expected_correction_payload).once().and_return( post_correction_ok_response)) post_response = client.post( '/product/{}/correction'.format(product_id), headers=valid_headers, data=json.dumps(submitted_correction_payload)) assert post_response.status_code == 201 @db.test_schema def test_post_product_correction_oa_updated_by( client, post_correction_ok_response, product_id, valid_headers): """Test that alw Orchard-User-Id populates last_updated as oa.""" valid_headers[header_constants.ORCHARD_USER_ID] = 'oa:123' existing_release = release_factory.ReleaseFactory.build( release_id=product_id) db.seed_models(existing_release) last_correction_response = mock.Mock(status_code=404) (flexmock(request).should_receive('get').with_args( services.OWS_PRODUCT_WORKFLOW, '/product/{}/correction'.format(product_id), ).and_return(last_correction_response)) expected_correction_payload = { 'last_updated_by': 123, 'last_updated_type': 'oa' } submitted_correction_payload = {} (flexmock(request).should_receive('post').with_args( services.OWS_PRODUCT_WORKFLOW, '/product/{}/correction'.format(product_id), json=expected_correction_payload).once().and_return( post_correction_ok_response)) post_response = client.post( '/product/{}/correction'.format(product_id), headers=valid_headers, data=json.dumps(submitted_correction_payload)) assert post_response.status_code == 201 def test_post_product_correction_not_owner( account_id, client, correction_data, product_id, valid_headers_for_vendor): """Test that a request is rejected if label does not own the product.""" not_owner_response = mock.MagicMock(status_code=403) (flexmock(request).should_receive('head').with_args( services.OWS_PRODUCT, '/vendor/{}/product/{}'.format(account_id, product_id)).and_return( not_owner_response)) post_response = client.post( '/product/{}/correction'.format(product_id), headers=valid_headers_for_vendor, data=json.dumps(correction_data)) assert post_response.status_code == 403 def test_post_product_correction_invalid_orchard_user( client, correction_data, product_id, valid_headers): """Test that a request is rejected if Orchard-User-Id header invalid.""" headers_with_bad_orchard_user_id = valid_headers headers_with_bad_orchard_user_id[ header_constants.ORCHARD_USER_ID] = 'Orchie McUserdude' post_response = client.post( '/product/{}/correction'.format(product_id), headers=headers_with_bad_orchard_user_id, data=json.dumps(correction_data)) post_response_body = json.loads(post_response.data.decode()) assert post_response.status_code == 400 assert header_constants.ORCHARD_USER_ID in post_response_body['message'] @db.test_schema def test_post_product_correction_active_correction( client, correction_data, product_id, valid_headers): """Test that a request is rejected if there is an active correction.""" existing_release = release_factory.ReleaseFactory.build( release_id=product_id) db.seed_models(existing_release) active_correction_response = mock.Mock(status_code=200) active_correction_response.json = mock.Mock( return_value={'status': 'active'}) (flexmock(request).should_receive('get').with_args( services.OWS_PRODUCT_WORKFLOW, '/product/{}/correction'.format(product_id), ).once().and_return(active_correction_response)) post_response = client.post( '/product/{}/correction'.format(product_id), headers=valid_headers, data=json.dumps(correction_data)) post_response_body = json.loads(post_response.data.decode()) assert post_response.status_code == 409 assert post_response_body == { 'code': 'correction_conflict', 'message': 'Product has a correction in "active" status' } @db.test_schema def test_post_product_correction_submitted_correction( client, correction_data, product_id, valid_headers): """Test that a request is rejected if there is a submitted correction.""" existing_release = release_factory.ReleaseFactory.build( release_id=product_id) db.seed_models(existing_release) active_correction_response = mock.Mock(status_code=200) active_correction_response.json = mock.Mock( return_value={'status': 'submitted'}) (flexmock(request).should_receive('get').with_args( services.OWS_PRODUCT_WORKFLOW, '/product/{}/correction'.format(product_id), ).once().and_return(active_correction_response)) post_response = client.post( '/product/{}/correction'.format(product_id), headers=valid_headers, data=json.dumps(correction_data)) post_response_body = json.loads(post_response.data.decode()) assert post_response.status_code == 409 assert post_response_body == { 'code': 'correction_conflict', 'message': 'Product has a correction in "submitted" status' } @db.test_schema def test_post_product_correction_applied_correction( client, correction_data, product_id, post_correction_ok_response, valid_headers): """Test that a request is successful if there is an applied correction.""" existing_release = release_factory.ReleaseFactory.build( release_id=product_id) db.seed_models(existing_release) last_correction_response = mock.Mock(status_code=200) last_correction_response.json = mock.Mock( return_value={'status': 'applied'}) (flexmock(request).should_receive('get').with_args( services.OWS_PRODUCT_WORKFLOW, '/product/{}/correction'.format(product_id), ).and_return(last_correction_response)) (flexmock(request).should_receive('post').with_args( services.OWS_PRODUCT_WORKFLOW, '/product/{}/correction'.format(product_id), json=correction_data).and_return(post_correction_ok_response)) post_response = client.post( '/product/{}/correction'.format(product_id), headers=valid_headers, data=json.dumps(correction_data)) assert post_response.status_code == 201