class CourseRunMarketingSitePublisherTests(MarketingSitePublisherTestMixin): """ Tests covering course run-specific publishing logic. """ def setUp(self): super().setUp() self.partner = PartnerFactory() self.publisher = CourseRunMarketingSitePublisher(self.partner) self.api_root = self.publisher.client.api_url self.username = self.publisher.client.username self.obj = CourseRunFactory() @mock.patch.object(CourseRunMarketingSitePublisher, 'node_id', return_value='node_id') @mock.patch.object(CourseRunMarketingSitePublisher, 'serialize_obj', return_value='data') @mock.patch.object(CourseRunMarketingSitePublisher, 'edit_node', return_value=None) def test_publish_obj(self, mock_edit_node, *args): # pylint: disable=unused-argument """ Verify that the publisher attempts to publish when course run status changes. """ # No previous object. No editing should occur. self.publisher.publish_obj(self.obj) assert not mock_edit_node.called # A previous object is provided, but the status hasn't changed. # No editing should occur. self.publisher.publish_obj(self.obj, previous_obj=self.obj) assert not mock_edit_node.called # A previous object is provided, and the status has changed. # Editing should occur. previous_obj = CourseRunFactory(status=CourseRunStatus.Unpublished) self.publisher.publish_obj(self.obj, previous_obj=previous_obj) mock_edit_node.assert_called_with('node_id', 'data') @responses.activate def test_serialize_obj(self): """ Verify that the publisher serializes data required to publish course runs. """ self.mock_api_client() actual = self.publisher.serialize_obj(self.obj) expected = { 'field_course_id': self.obj.key, 'author': { 'id': self.user_id }, 'status': 1, } assert actual == expected self.obj.status = CourseRunStatus.Unpublished actual = self.publisher.serialize_obj(self.obj) expected['status'] = 0 assert actual == expected
class CourseRunMarketingSitePublisherTests(MarketingSitePublisherTestMixin): """ Tests covering course run-specific publishing logic. """ def setUp(self): super().setUp() self.partner = PartnerFactory() self.publisher = CourseRunMarketingSitePublisher(self.partner) self.api_root = self.publisher.client.api_url self.username = self.publisher.client.username self.obj = CourseRunFactory() @mock.patch.object(CourseRunMarketingSitePublisher, 'node_id', return_value=None) @mock.patch.object(CourseRunMarketingSitePublisher, 'create_node') def test_publish_obj_create_disabled(self, mock_create_node, mock_node_id): self.publisher.publish_obj(self.obj) mock_node_id.assert_called_with(self.obj) assert not mock_create_node.called @mock.patch.object(CourseRunMarketingSitePublisher, 'serialize_obj', return_value={'data': 'test'}) @mock.patch.object(CourseRunMarketingSitePublisher, 'node_id', return_value=None) @mock.patch.object(CourseRunMarketingSitePublisher, 'create_node', return_value='node_id') @mock.patch.object(CourseRunMarketingSitePublisher, 'update_node_alias') @override_switch('auto_course_about_page_creation', True) def test_publish_obj_create_successful(self, mock_update_node_alias, mock_create_node, *args): # pylint: disable=unused-argument self.publisher.publish_obj(self.obj) mock_create_node.assert_called_with({ 'data': 'test', 'field_course_uuid': str(self.obj.uuid) }) mock_update_node_alias.assert_called_with(self.obj, 'node_id', None) @mock.patch.object(CourseRunMarketingSitePublisher, 'node_id', return_value=None) @mock.patch.object(CourseRunMarketingSitePublisher, 'serialize_obj', return_value={'data': 'test'}) @mock.patch.object(CourseRunMarketingSitePublisher, 'create_node', return_value='node1') @mock.patch.object(CourseRunMarketingSitePublisher, 'update_node_alias') @override_switch('auto_course_about_page_creation', True) def test_publish_obj_create_if_exists_on_discovery(self, mock_update_node_alias, mock_create_node, mock_serialize_obj, mock_node_id, *args): # pylint: disable=unused-argument self.publisher.publish_obj(self.obj) mock_node_id.assert_called_with(self.obj) mock_serialize_obj.assert_called_with(self.obj) mock_create_node.assert_called_with({ 'data': 'test', 'field_course_uuid': str(self.obj.uuid) }) mock_update_node_alias.assert_called_with(self.obj, 'node1', None) @mock.patch.object(CourseRunMarketingSitePublisher, 'node_id', return_value='node_id') @mock.patch.object(CourseRunMarketingSitePublisher, 'serialize_obj', return_value='data') @mock.patch.object(CourseRunMarketingSitePublisher, 'edit_node', return_value=None) @mock.patch.object(CourseRunMarketingSitePublisher, 'update_node_alias') def test_publish_obj_edit(self, mock_node_alias, mock_edit_node, *args): # pylint: disable=unused-argument """ Verify that the publisher attempts to publish when course run status changes. """ # A previous object is provided, but the status hasn't changed. # No editing should occur. self.publisher.publish_obj(self.obj, previous_obj=self.obj) assert not mock_edit_node.called # A previous object is provided, and the status has changed. # Editing should occur. previous_obj = CourseRunFactory(status=CourseRunStatus.Unpublished) self.publisher.publish_obj(self.obj, previous_obj=previous_obj) mock_edit_node.assert_called_with('node_id', 'data') mock_node_alias.assert_called_with(self.obj, 'node_id', None) @responses.activate def test_serialize_obj(self): """ Verify that the publisher serializes data required to publish course runs. """ self.mock_api_client() actual = self.publisher.serialize_obj(self.obj) expected = { 'field_course_id': self.obj.key, 'title': self.obj.title, 'author': { 'id': self.user_id }, 'status': 1, 'type': 'course', } assert actual == expected self.obj.status = CourseRunStatus.Unpublished actual = self.publisher.serialize_obj(self.obj) expected['status'] = 0 assert actual == expected @responses.activate def test_update_node_alias(self): """ Verify that the publisher attempts to create a new alias associated with the new course_run, and that appropriate exceptions are raised for non-200 status codes. """ # No previous object is provided. Create a new node and make sure # title alias created, by default, based on the title is deleted # and a new alias based on marketing slug is created. self.mock_api_client() self.mock_get_alias_form() self.mock_get_delete_form(self.obj.slug) self.mock_delete_alias() self.mock_get_delete_form(self.obj.slug) self.mock_add_alias() self.publisher.update_node_alias(self.obj, self.node_id, None) assert responses.calls[-1].request.url == '{}/add'.format( self.publisher.alias_api_base) responses.reset() # Same scenario, but this time a non-200 status code is returned during # alias creation. An exception should be raised. self.mock_api_client() self.mock_get_alias_form() self.mock_get_delete_form(self.obj.slug) self.mock_delete_alias() self.mock_get_delete_form(self.obj.slug) self.mock_add_alias(status=500) with pytest.raises(AliasCreateError): self.publisher.update_node_alias(self.obj, self.node_id, None) responses.reset() # A previous object is provided, but the marketing slug hasn't changed. # Neither alias creation nor alias deletion should occur. self.mock_api_client() self.mock_get_delete_form(self.obj.slug) self.publisher.update_node_alias(self.obj, self.node_id, self.obj) responses.reset() # In this case, similate the fact that alias form retrival returned error # FormRetrievalError should be raised self.mock_api_client() self.mock_get_delete_form(self.obj.slug) self.mock_get_alias_form(status=500) with pytest.raises(FormRetrievalError): self.publisher.update_node_alias(self.obj, self.node_id, None) def test_alias(self): """ Verify that aliases are constructed correctly. """ actual = self.publisher.alias(self.obj) expected = 'course/{slug}'.format(slug=self.obj.slug) assert actual == expected