def get_updated_content_and_parent(update_field): """Run update_content_from_s3_data with test data and return content, parent""" website = WebsiteFactory.build() content = WebsiteContentFactory.build( markdown="original markdown", metadata={"title": "original title"}, website=website, ) content.save = Mock() # prepare the parent, but do not set content.parent_id. # that's one of the things we'll test parent = WebsiteContentFactory.build(id=123) s3_content_data = { "markdown": "s3 markdown", "metadata": { "title": "s3 title", "author": "s3 author", "parent_uid": "s3_parent_uid", }, "parent": parent, } with patch("websites.models.WebsiteContent.objects") as mock: mock.filter.return_value.first.return_value = content website = content.website text_id = content.text_id update_content_from_s3_data(website, text_id, s3_content_data, update_field) return content, parent
def test_baseurl_replacer_handle_specific_url_replacements( url, content_relative_dirpath, filename ): """ Test specific replacements This test could perhaps be dropped. It was written before ContentLookup was moved to a separate module, and the functionality is tested their, now, too. """ website_uuid = "website-uuid" website = WebsiteFactory.build(uuid=website_uuid) markdown = f"my [pets]({{{{< baseurl >}}}}{url}) are legion" expected_markdown = 'my {{% resource_link content-uuid "pets" %}} are legion' target_content = WebsiteContentFactory.build(markdown=markdown, website=website) linkable = WebsiteContentFactory.build( website=website, dirpath=f"content{content_relative_dirpath}", filename=filename, text_id="content-uuid", ) cleaner = get_markdown_cleaner([linkable]) cleaner.update_website_content(target_content) assert target_content.markdown == expected_markdown
def test_baseurl_replacer_replaces_content_in_same_course( website_uuid, should_markdown_change ): """ Double check that if the dirpath + filename match multiple times, the content chosen is from the same course as the markdown being edited """ markdown = R""" Kittens [meow]({{< baseurl >}}/resources/pets/cat) meow. """ w1 = WebsiteFactory.build(uuid="website-uuid-111") w2 = WebsiteFactory.build(uuid="website-uuid-222") websites = {w.uuid: w for w in [w1, w2]} target_content = WebsiteContentFactory.build(markdown=markdown, website=w1) linkable = WebsiteContentFactory.build( website=websites[website_uuid], dirpath="content/resources/pets", filename="cat", text_id="uuid-111", ) cleaner = get_markdown_cleaner([linkable]) cleaner.update_website_content(target_content) is_markdown_changed = target_content.markdown != markdown assert is_markdown_changed == should_markdown_change
def test_resolveuid_conversion_within_same_site(markdown, expected): """Check shortcodes are used within same site.""" website = WebsiteFactory.build() target_content = WebsiteContentFactory.build(markdown=markdown, website=website) linked_content = WebsiteContentFactory.build( text_id="5cf754b2-b97b-4ac1-8dab-deed1201de94", website=website ) cleaner = get_markdown_cleaner([target_content, linked_content]) cleaner.update_website_content(target_content) assert target_content.markdown == expected
def test_updates_multiple_metadata_fields(): """ Check that a single call to update_website_content modifies multiple fields for rules that have multiple fields associated. """ assert len(MetadataRelativeUrlsFix.fields) > 1 website = WebsiteFactory.build(name="site-1") wc1 = WebsiteContentFactory.build( filename="thing1", dirpath="content/resources", website=website, ) wc2 = WebsiteContentFactory.build(filename="thing2", dirpath="content/pages/two", website=website) content_to_clean = WebsiteContentFactory.build( metadata={ "related_resources_text": """Hello Change this: [to thing1](resources/thing1#fragment "And a title!") cool' Leave this alone: [wiki](https://wikipedia.org) same And this [course link](/courses/8-02/pages/jigawatts) """, "image_metadata": { "caption": "And now [thing2](pages/two/thing2)" }, }, website=website, ) cleaner = get_markdown_cleaner([wc1, wc2]) cleaner.update_website_content(content_to_clean) expected_related_resources = """Hello Change this: [to thing1](/courses/site-1/resources/thing1#fragment) cool' Leave this alone: [wiki](https://wikipedia.org) same And this [course link](/courses/8-02/pages/jigawatts) """ expected_caption = "And now [thing2](/courses/site-1/pages/two/thing2)" assert (content_to_clean.metadata["related_resources_text"] == expected_related_resources) assert content_to_clean.metadata["image_metadata"][ "caption"] == expected_caption
def test_get_destination_filepath_errors(mocker, has_missing_name, is_bad_config_item): """ get_destination_filepath should log an error and return None if the site config is missing the given name, or if the config item does not have a properly configured destination. """ patched_log = mocker.patch("content_sync.utils.log") # From basic-site-config.yml config_item_name = "blog" if is_bad_config_item: mocker.patch.object( SiteConfig, "find_item_by_name", return_value=ConfigItem(item={ "name": config_item_name, "poorly": "configured" }), ) starter = WebsiteStarterFactory.build() content = WebsiteContentFactory.build( is_page_content=False, type="non-existent-config-name" if has_missing_name else config_item_name, ) return_value = get_destination_filepath(content=content, site_config=SiteConfig( starter.config)) patched_log.error.assert_called_once() assert return_value is None
def test_resolveuid_conversion_cross_site(markdown, expected): """Check shortcodes are used within same site.""" target_content = WebsiteContentFactory.build( markdown=markdown, website=WebsiteFactory.build() ) linked_content = WebsiteContentFactory.build( text_id="5cf754b2-b97b-4ac1-8dab-deed1201de94", dirpath="content/pages/path/to", filename="thing", website=WebsiteFactory.build(name="other-site-name"), ) cleaner = get_markdown_cleaner([target_content, linked_content]) cleaner.update_website_content(target_content) assert target_content.markdown == expected
def test_hugo_menu_yaml_serialize(omnibus_config): """HugoMenuYamlFileSerializer.serialize should create the expected file contents""" nav_menu_config_item = omnibus_config.find_item_by_name("navmenu") assert nav_menu_config_item is not None # Create page object referred to in the menu data WebsiteContentFactory.create( text_id=EXAMPLE_UUIDS[0], is_page_content=True, dirpath="path/to", filename="myfile", ) example_menu_data = get_example_menu_data() content = WebsiteContentFactory.build( is_page_content=False, type=nav_menu_config_item.name, metadata={"mainmenu": example_menu_data}, ) serialized_data = HugoMenuYamlFileSerializer(omnibus_config).serialize(content) parsed_serialized_data = yaml.load(serialized_data, Loader=yaml.SafeLoader) assert parsed_serialized_data == { "mainmenu": [ {**example_menu_data[0], "url": "/path/to/myfile"}, example_menu_data[1], ] }
def test_legacy_shortcode_fix_one(markdown, expected_markdown): """Test specific replacements""" website = WebsiteFactory.build() target_content = WebsiteContentFactory.build(markdown=markdown, website=website) cleaner = Cleaner(LegacyShortcodeFixOne()) cleaner.update_website_content(target_content) assert target_content.markdown == expected_markdown
def test_content_finder_returns_metadata_for_site(site_uuid, content_index): contents = [ WebsiteContentFactory.build( website=WebsiteFactory.build(uuid="website_one"), type="sitemetadata", text_id="content-1", ), WebsiteContentFactory.build( website=WebsiteFactory.build(uuid="website_two"), type="sitemetadata", text_id="content-2", ), ] with patch_website_contents_all(contents): content_lookup = ContentLookup() assert (content_lookup.find_within_site( site_uuid, "/") == contents[content_index])
def test_rootrel_rule_only_uses_resource_lines_for_same_site( markdown, site_name, expected_markdown): w1 = WebsiteFactory.build(name="site_one") w2 = WebsiteFactory.build(name="site_two") websites = {w.name: w for w in [w1, w2]} c1 = WebsiteContentFactory.build(website=w1, filename="page1", dirpath="content/pages/stuff", text_id="uuid-1") content_to_clean = WebsiteContentFactory.build(website=websites[site_name], markdown=markdown) cleaner = get_markdown_cleaner([w1], [c1]) cleaner.update_website_content(content_to_clean) assert content_to_clean.markdown == expected_markdown
def test_legacy_file_lookup_raises_nonunique_for_multiple_matches(): c1a = WebsiteContentFactory.build( website_id="site-uuid-one", file=f"/courses/site_one/{string_uuid()}_some_file_name.jpg", text_id="content-uuid-1", ) c1b = WebsiteContentFactory.build( website_id="site-uuid-one", file=f"/courses/site_one/{string_uuid()}_some_file_name.jpg", text_id="content-uuid-2", ) contents = [c1a, c1b] with patch_website_contents_all(contents): legacy_file_lookup = LegacyFileLookup() with pytest.raises(legacy_file_lookup.MultipleMatchError): assert legacy_file_lookup.find("site-uuid-one", "some_file_name.jpg")
def test_rootrel_rule_handles_site_homeages_correctly(markdown, site_name, expected_markdown): w1 = WebsiteFactory.build(name="site_one") w2 = WebsiteFactory.build(name="site_two") websites = {w.name: w for w in [w1, w2]} c1 = WebsiteContentFactory.build(website=w1, type="sitemetadata", filename="", dirpath="", text_id="uuid-1") content_to_clean = WebsiteContentFactory.build(website=websites[site_name], markdown=markdown) cleaner = get_markdown_cleaner([w1], [c1]) cleaner.update_website_content(content_to_clean) assert content_to_clean.markdown == expected_markdown
def test_baseurl_replacer_specific_title_replacements(markdown, expected_markdown): """Test specific replacements""" website_uuid = "website-uuid" website = WebsiteFactory.build(uuid=website_uuid) target_content = WebsiteContentFactory.build(markdown=markdown, website=website) linkable = WebsiteContentFactory.build( website=website, dirpath="content/resources/path/to", filename="file1", text_id="content-uuid-1", ) cleaner = get_markdown_cleaner([linkable]) cleaner.update_website_content(target_content) assert target_content.markdown == expected_markdown
def test_shortcode_standardizer(text, expected): """Check that it removes extra args from resource shortcodes""" target_content = WebsiteContentFactory.build( markdown=text, website=WebsiteFactory.build()) cleaner = get_markdown_cleaner() cleaner.update_website_content(target_content) assert target_content.markdown == expected
def test_websitecontent_full_metadata(has_file_widget, has_file): """WebsiteContent.full_metadata returns expected file field in metadata when appropriate""" file = SimpleUploadedFile("test.txt", b"content") title = ("Test Title", ) description = "Test Description" config_fields = [ { "label": "Description", "name": "description", "widget": "text" }, { "label": "My File", "name": "my_file", "widget": "file", "required": False }, ] site_config = { "content-dir": "content", "collections": [{ "name": "resource", "label": "Resource", "category": "Content", "folder": "content/resource", "fields": config_fields if has_file_widget else config_fields[0:1], }], } starter = WebsiteStarterFactory.create(config=site_config) content = WebsiteContentFactory.build( type="resource", metadata={ "title": title, "description": description }, file=(file if has_file else None), website=WebsiteFactory(starter=starter), ) if has_file_widget: assert content.full_metadata == { "title": title, "description": description, "my_file": content.file.url if has_file else None, } else: assert content.full_metadata == { "title": title, "description": description }
def test_resolveuid_leaves_stuff_alone_if_it_should(markdown, expected): """Check shortcodes are used within same site.""" target_content = WebsiteContentFactory.build( markdown=markdown, website=WebsiteFactory.build() ) cleaner = get_markdown_cleaner([target_content]) cleaner.update_website_content(target_content) assert target_content.markdown == expected
def test_factory_for_content_hugo_markdown(): """ ContentFileSerializerFactory.for_content should return the Hugo markdown serializer if the content object is page content. """ content = WebsiteContentFactory.build(is_page_content=True) site_config = SiteConfig(content.website.starter.config) assert isinstance( ContentFileSerializerFactory.for_content(site_config, content), HugoMarkdownFileSerializer, )
def test_baseurl_replacer_handles_index_files(): """Test specific replacements""" website_uuid = "website-uuid" website = WebsiteFactory.build(uuid=website_uuid) markdown = R"my [pets]({{< baseurl >}}/pages/cute/pets) are legion" expected_markdown = R'my {{% resource_link content-uuid "pets" %}} are legion' target_content = WebsiteContentFactory.build(markdown=markdown, website=website) linkable = WebsiteContentFactory.build( website=website, dirpath="content/pages/cute/pets", filename="_index", text_id="content-uuid", ) cleaner = get_markdown_cleaner([linkable]) cleaner.update_website_content(target_content) assert linkable.filename not in target_content.markdown assert target_content.markdown == expected_markdown
def test_get_rootrelative_url_from_content(): c1 = WebsiteContentFactory.build( website=WebsiteFactory.build(name="site-name-1"), dirpath="content/pages/path/to", filename="file1", ) c2 = WebsiteContentFactory.build( website=WebsiteFactory.build(name="site-name-2"), dirpath="content/pages/assignments", filename="_index", ) c3 = WebsiteContentFactory.build( website=WebsiteFactory.build(name="site-THREE"), dirpath="content/resources/long/path/to", filename="file3", ) urls = [get_rootrelative_url_from_content(c) for c in [c1, c2, c3]] assert urls[0] == "/courses/site-name-1/pages/path/to/file1" assert urls[1] == "/courses/site-name-2/pages/assignments" assert urls[2] == "/courses/site-THREE/resources/long/path/to/file3"
def test_rootrel_rule_uses_images_for_image(markdown, site_name, expected_markdown): w1 = WebsiteFactory.build(name="site_one") w2 = WebsiteFactory.build(name="site_two") websites = {w.name: w for w in [w1, w2]} c1 = WebsiteContentFactory.build( website=w1, text_id="uuid-1", file= f"only/last/part/matters/for/now/{string_uuid()}_old_image_filename123.jpg", # in general the new filename is the same as old, # possibly appended with "-1" or "-2" if there were duplicates filename="new_image_filename123.jpg", dirpath="content/resources", ) content_to_clean = WebsiteContentFactory.build(website=websites[site_name], markdown=markdown) cleaner = get_markdown_cleaner([w1], [c1]) cleaner.update_website_content(content_to_clean) assert content_to_clean.markdown == expected_markdown
def test_legacy_file_lookup(site_uuid, filename, expected_index): c1a = WebsiteContentFactory.build( website_id="site-uuid-one", file=f"/courses/site_one/{string_uuid()}_someFileName.jpg", text_id="content-uuid-1a", ) c1b = WebsiteContentFactory.build( website_id="site-uuid-one", file=f"/courses/site_one/{string_uuid()}_somefilename.jpg", text_id="content-uuid-1b", ) c2 = WebsiteContentFactory.build( website_id="site-uuid-two", file=f"/courses/site_two/{string_uuid()}_someFileName.jpg", text_id="content-uuid-two", ) contents = [c1a, c1b, c2] expected = contents[expected_index] with patch_website_contents_all(contents): legacy_file_lookup = LegacyFileLookup() assert legacy_file_lookup.find(site_uuid, filename) == expected
def test_websitecontent_calculate_checksum(metadata, markdown, dirpath, exp_checksum): """ Verify calculate_checksum() returns the expected sha256 checksum """ content = WebsiteContentFactory.build( markdown=markdown, metadata=metadata, dirpath=dirpath, filename="myfile", type="mytype", title="My Title", ) # manually computed checksum in a python shell assert content.calculate_checksum() == exp_checksum
def test_content_finder_is_site_specific(): """Test that ContentLookup is site specific""" content_w1 = WebsiteContentFactory.build( website=WebsiteFactory.build(uuid="website-uuid-1"), dirpath="content/resources/path/to", filename="file1", text_id="content-uuid-1", ) content_w2 = WebsiteContentFactory.build( website=WebsiteFactory.build(uuid="website-uuid-2"), dirpath="content/resources/path/to", filename="file1", text_id="content-uuid-1", ) with patch_website_contents_all([content_w1, content_w2]): content_lookup = ContentLookup() url = "/resources/path/to/file1" assert content_lookup.find_within_site(content_w1.website_id, url) == content_w1 assert content_lookup.find_within_site(content_w2.website_id, url) == content_w2
def test_content_finder_specific_url_replacements(url, content_relative_dirpath, filename): content = WebsiteContentFactory.build( website=WebsiteFactory.build(uuid="website_uuid"), dirpath=f"content{content_relative_dirpath}", filename=filename, text_id="content-uuid", ) with patch_website_contents_all([content]): content_lookup = ContentLookup() assert content_lookup.find_within_site("website_uuid", url) == content
def test_factory_for_content_hugo_menu(omnibus_config): """ ContentFileSerializerFactory.for_content should return the Hugo menu serializer class if the content is associated with a config item that has "menu" fields """ nav_menu_config_item = omnibus_config.find_item_by_name("navmenu") assert nav_menu_config_item is not None content = WebsiteContentFactory.build( is_page_content=False, type=nav_menu_config_item.name ) assert isinstance( ContentFileSerializerFactory.for_content( site_config=omnibus_config, website_content=content ), HugoMenuYamlFileSerializer, )
def test_shortcode_standardizer(): """Check that it replaces resource_file links as expected""" markdown = R""" Roar {{< cat uuid "some \"text\" cool">}} {{< dog a b >}} Hello world {{< wolf "a b" >}} """ target_content = WebsiteContentFactory.build( markdown=markdown, website=WebsiteFactory.build()) cleaner = get_markdown_cleaner() cleaner.update_website_content(target_content) assert target_content.markdown == markdown
def test_get_destination_url_errors(mocker): """ get_destination_url should log an error if it is called with a a WebsiteContent object without is_page_content set to true """ patched_log = mocker.patch("content_sync.utils.log") # From basic-site-config.yml config_item_name = "blog" starter = WebsiteStarterFactory.build() content = WebsiteContentFactory.build( is_page_content=False, type=config_item_name, ) return_value = get_destination_url(content=content, site_config=SiteConfig(starter.config)) patched_log.error.assert_called_once() assert return_value is None
def test_serialize_content_to_file(mocker): """serialize_content_to_file should pick the correct serializer class and serialize a website content object""" mock_serializer = mocker.MagicMock(spec=BaseContentFileSerializer) patched_serializer_factory = mocker.patch( "content_sync.serializers.ContentFileSerializerFactory", autospec=True ) patched_serializer_factory.for_content.return_value = mock_serializer website_content = WebsiteContentFactory.build() site_config = SiteConfig(website_content.website.starter.config) serialized = serialize_content_to_file( site_config=site_config, website_content=website_content ) patched_serializer_factory.for_content.assert_called_once_with( site_config, website_content ) mock_serializer.serialize.assert_called_once_with(website_content=website_content) assert serialized == mock_serializer.serialize.return_value
def test_factory_for_content_data(file_value, exp_serializer_cls): """ ContentFileSerializerFactory.for_content should return the correct data file serializer when given a content object that was created for a "file"-type config item. """ content = WebsiteContentFactory.build(is_page_content=False, type="sometype") site_config = SiteConfig(content.website.starter.config) # Create a new "file"-type config item which will match our website content object raw_files_item = next( raw_config_item for raw_config_item in site_config.raw_data["collections"] if "files" in raw_config_item ) new_files_item = raw_files_item.copy() new_files_item["name"] = "newfiles" new_files_item["files"] = [ {**raw_files_item["files"][0].copy(), "name": content.type, "file": file_value} ] site_config.raw_data["collections"].append(new_files_item) assert isinstance( ContentFileSerializerFactory.for_content(site_config, content), exp_serializer_cls, )