def test_post_render_config_with_clean_urls(self): with TemporaryDirectory() as output_directory_path: configuration = Configuration( output_directory_path, 'http://example.com') configuration.plugins[Nginx] = {} configuration.clean_urls = True site = Site(configuration) render(site) expected = '''server { listen 80; server_name example.com; root %s; add_header Cache-Control "max-age=86400"; gzip on; gzip_disable "msie6"; gzip_vary on; gzip_types text/css application/javascript application/json application/xml; set $content_type_extension html; index index.$content_type_extension; location / { # Handle HTTP error responses. error_page 401 /.error/401.$content_type_extension; error_page 403 /.error/403.$content_type_extension; error_page 404 /.error/404.$content_type_extension; location /.error { internal; } try_files $uri $uri/ =404; } }''' % configuration.www_directory_path # noqa: E101 W191 with open(join(configuration.output_directory_path, 'nginx', 'nginx.conf')) as f: # noqa: E101 self.assertEquals(expected, f.read())
async def test_front_page(self): configuration = Configuration(self._output_directory.name, 'https://ancestry.example.com') app = App(configuration) async with app: await generate(app) self.assert_betty_html(app, '/index.html')
async def _render(self, data: Optional[Dict] = None, template_file: Optional[Template] = None, template_string: Optional[str] = None, update_configuration: Optional[Callable[[Configuration], None]] = None) -> Tuple[str, Site]: if template_string is not None and template_file is not None: raise RuntimeError('You must define either `template_string` or `template_file`, but not both.') if template_string is not None: template = template_string template_factory = Environment.from_string elif template_file is not None: template = template_file template_factory = Environment.get_template elif self.template_string is not None: template = self.template_string template_factory = Environment.from_string elif self.template_file is not None: template = self.template_file template_factory = Environment.get_template else: class_name = self.__class__.__name__ raise RuntimeError(f'You must define one of `template_string`, `template_file`, `{class_name}.template_string`, or `{class_name}.template_file`.') if data is None: data = {} with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.mode = 'development' if update_configuration is not None: update_configuration(configuration) async with Site(configuration) as site: rendered = await template_factory(site.jinja2_environment, template).render_async(**data) # We want to keep the site around, but we must make sure all dispatched tasks are done, so we shut down # the executor. Crude, but effective. site.executor.shutdown() yield rendered, site
async def test_post_parse(self): person = Person('P0') Presence(person, Subject(), Event(Birth())) source_file = File('F0', __file__) source = IdentifiableSource('S0', 'The Source') source.private = True source.files.append(source_file) citation_file = File('F0', __file__) citation_source = Source('The Source') citation = IdentifiableCitation('C0', citation_source) citation.private = True citation.files.append(citation_file) with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.plugins[Privatizer] = None async with Site(configuration) as site: site.ancestry.people[person.id] = person site.ancestry.sources[source.id] = source site.ancestry.citations[citation.id] = citation await parse(site) self.assertTrue(person.private) self.assertTrue(source_file.private) self.assertTrue(citation_file.private)
def test_with_one_plugin(self): configuration = Configuration(**self._MINIMAL_CONFIGURATION_ARGS) configuration.plugins[NonConfigurablePlugin] = {} sut = Site(configuration) self.assertEquals(1, len(sut.plugins)) self.assertIsInstance( sut.plugins[NonConfigurablePlugin], NonConfigurablePlugin)
def test_with_unknown_plugin_class(self): with TemporaryDirectory() as www_directory_path: environment = create_environment( Site(Configuration(www_directory_path, 'https://example.com'))) template = '{% if "betty.UnknownPlugin" in plugins %}true{% else %}false{% endif %}' self.assertEquals('false', environment.from_string(template).render())
async def test_populate_should_populate_existing_link(self, m_retriever) -> None: entry_language = 'en' entry_name = 'Amsterdam' entry_title = 'Amsterdam' entry_content = 'Capitol of the Netherlands' entry = Entry(entry_language, entry_name, entry_title, entry_content) m_retriever.get_entry.return_value = entry resource = IdentifiableSource('the_source', 'The Source') link = Link('https://en.wikipedia.org/wiki/Amsterdam') resource.links.add(link) with TemporaryDirectory() as output_directory_path: with TemporaryDirectory() as cache_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.cache_directory_path = cache_directory_path async with Site(configuration) as site: site.ancestry.sources[resource.id] = resource sut = _Populator(site, m_retriever) await sut.populate() m_retriever.get_entry.assert_called_once_with(entry_language, entry_name) self.assertEqual(1, len(resource.links)) self.assertEqual('Amsterdam', link.label) self.assertEqual('en', link.locale) self.assertEqual(MediaType('text/html'), link.media_type) self.assertIsNotNone(link.description) self.assertEqual('external', link.relationship)
def test_output_directory_path_with_relative_path(self): output_directory_path = './betty' sut = Configuration(output_directory_path, 'https://example.com') site_directory_path = '/tmp/betty-working-directory' sut.site_directory_path = site_directory_path self.assertEquals('/tmp/betty-working-directory/betty', sut.output_directory_path)
def test_resources_with_resources_directory_path(self): resources_directory_path = '/tmp/betty' configuration = Configuration(**self._MINIMAL_CONFIGURATION_ARGS) configuration.resources_directory_path = resources_directory_path sut = Site(configuration) self.assertEquals(2, len(sut.resources.paths)) self.assertEquals(resources_directory_path, sut.resources.paths[0])
def setUpClass(cls): cls._outputDirectory = TemporaryDirectory() configuration = Configuration(cls._outputDirectory.name, 'https://ancestry.example.com') cls.site = Site(configuration) place1 = Place('PLACE1', 'one') event1 = Event('EVENT1', Event.Type.BIRTH) event1.place = place1 event1_person_1_presence = Presence(Presence.Role.SUBJECT) event1_person_1_presence.event = event1 person1 = Person('PERSON1', 'Janet', 'Dough') person1.presences.add(event1_person_1_presence) source1 = Source('SOURCE1', 'A Little Birdie') places = [place1] cls.site.ancestry.places.update({place.id: place for place in places}) events = [event1] cls.site.ancestry.events.update({event.id: event for event in events}) people = [person1] cls.site.ancestry.people.update( {person.id: person for person in people}) sources = [source1] cls.site.ancestry.sources.update( {source.id: source for source in sources}) render(cls.site)
def test(self, expected, template, data): with TemporaryDirectory() as www_directory_path: environment = create_environment( Site(Configuration(www_directory_path, 'https://example.com'))) self.assertEquals( expected, environment.from_string(template).render(data=data))
async def test_resources_with_assets_directory_path(self): assets_directory_path = '/tmp/betty' configuration = Configuration(**self._MINIMAL_CONFIGURATION_ARGS) configuration.assets_directory_path = assets_directory_path async with Site(configuration) as sut: self.assertEquals(2, len(sut.assets.paths)) self.assertEquals(assets_directory_path, sut.assets.paths[0])
async def test_filter(self, m_aioresponses) -> None: entry_url = 'https://en.wikipedia.org/wiki/Amsterdam' links = [ Link(entry_url), # Add a link to Wikipedia, but using a locale that's not used by the site, to test it's ignored. Link('https://nl.wikipedia.org/wiki/Amsterdam'), # Add a link that doesn't point to Wikipedia at all to test it's ignored. Link('https://example.com'), ] api_url = 'https://en.wikipedia.org/w/api.php?action=query&titles=Amsterdam&prop=extracts&exintro&format=json&formatversion=2' title = 'Amstelredam' extract = 'De hoofdstad van Nederland.' api_response_body = { 'query': { 'pages': [ { 'title': title, 'extract': extract, }, ], } } m_aioresponses.get(api_url, payload=api_response_body) with TemporaryDirectory() as output_directory_path: with TemporaryDirectory() as cache_directory_path: configuration = Configuration(output_directory_path, 'https://ancestry.example.com') configuration.cache_directory_path = cache_directory_path configuration.plugins[Wikipedia] = None async with Site(configuration) as site: actual = await site.jinja2_environment.from_string( '{% for entry in (links | wikipedia) %}{{ entry.content }}{% endfor %}' ).render_async(links=links) self.assertEquals(extract, actual)
def test_filter(self, m_expanduser, m_requests): with TemporaryDirectory() as cache_directory_path: m_expanduser.side_effect = lambda _: cache_directory_path with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://ancestry.example.com') configuration.plugins[Wikipedia] = {} environment = create_environment(Site(configuration)) page_uri = 'https://en.wikipedia.org/wiki/Amsterdam' link = Link(page_uri) api_uri = 'https://en.wikipedia.org/w/api.php?action=query&titles=Amsterdam&prop=extracts&exintro&format=json&formatversion=2' title = 'Amstelredam' extract = 'De hoofdstad van Nederland.' api_response_body = { 'query': { 'pages': [ { 'title': title, 'extract': extract, }, ], } } m_requests.register_uri('GET', api_uri, json=api_response_body) actual = environment.from_string( '{% for entry in ([link] | wikipedia) %}{{ entry.content }}{% endfor %}' ).render(link=link) self.assertEquals(extract, actual)
async def test_post_render_config_with_clean_urls(self): with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'http://example.com') configuration.plugins[Nginx] = {} configuration.clean_urls = True expected = r''' server { listen 80; server_name example.com; root %s; add_header Cache-Control "max-age=86400"; gzip on; gzip_disable "msie6"; gzip_vary on; gzip_types text/css application/javascript application/json application/xml; set $media_type_extension html; index index.$media_type_extension; location / { # Handle HTTP error responses. error_page 401 /.error/401.$media_type_extension; error_page 403 /.error/403.$media_type_extension; error_page 404 /.error/404.$media_type_extension; location /.error { internal; } try_files $uri $uri/ =404; } } ''' % configuration.www_directory_path await self._assert_configuration_equals(expected, configuration)
async def test_post_load(self): person = Person('P0') Presence(person, Subject(), Event(None, Birth())) source_file = File('F0', __file__) source = Source('S0', 'The Source') source.private = True source.files.append(source_file) citation_file = File('F0', __file__) citation_source = Source('The Source') citation = Citation('C0', citation_source) citation.private = True citation.files.append(citation_file) with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.extensions.add(ExtensionConfiguration(Privatizer)) async with App(configuration) as app: app.ancestry.entities.append(person) app.ancestry.entities.append(source) app.ancestry.entities.append(citation) await load(app) self.assertTrue(person.private) self.assertTrue(source_file.private) self.assertTrue(citation_file.private)
async def test_with_one_extension(self): configuration = Configuration(**self._MINIMAL_CONFIGURATION_ARGS) configuration.extensions[NonConfigurableExtension] = None async with App(configuration) as sut: self.assertEquals(1, len(sut.extensions)) self.assertIsInstance( sut.extensions[NonConfigurableExtension], NonConfigurableExtension)
async def test_extensions_with_one_extension(self) -> None: configuration = Configuration(**self._MINIMAL_CONFIGURATION_ARGS) configuration.extensions.add( ExtensionConfiguration(NonConfigurableExtension)) async with App(configuration) as sut: self.assertIsInstance(sut.extensions[NonConfigurableExtension], NonConfigurableExtension)
async def test_extensions_with_multiple_extensions_with_cyclic_dependencies( self) -> None: configuration = Configuration(**self._MINIMAL_CONFIGURATION_ARGS) configuration.extensions.add( ExtensionConfiguration(CyclicDependencyOneExtension)) with self.assertRaises(CycleError): async with App(configuration) as sut: sut.extensions
async def test_xml_tar_gz(self): with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') async with Site(configuration) as site: gramps_file_path = join(dirname(abspath(__file__)), 'assets', 'minimal.gpkg') parse_xml(site, gramps_file_path)
def test_resources_directory_path_with_relative_path(self): sut = Configuration('/tmp/betty', 'https://example.com') site_directory_path = '/tmp/betty-working-directory' sut.site_directory_path = site_directory_path resources_directory_path = './betty-resources' sut.resources_directory_path = resources_directory_path self.assertEquals( '/tmp/betty-working-directory/betty-resources', sut.resources_directory_path)
async def test(self): with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://ancestry.example.com') configuration.extensions[ReDoc] = None async with App(configuration) as app: await generate(app) self.assertTrue(path.isfile(path.join(output_directory_path, 'www', 'api', 'index.html'))) self.assertTrue(path.isfile(path.join(output_directory_path, 'www', 'redoc.js')))
async def test_assets_with_assets_directory_path(self) -> None: assets_directory_path = Path('/tmp/betty') configuration = Configuration(**self._MINIMAL_CONFIGURATION_ARGS) configuration.assets_directory_path = assets_directory_path async with App(configuration) as sut: self.assertEquals(2, len(sut.assets.paths)) self.assertEquals((assets_directory_path, None), sut.assets.paths[0])
def setUp(self): GenerateTestCase.setUp(self) configuration = Configuration( self._outputDirectory.name, 'https://ancestry.example.com') configuration.locales.clear() configuration.locales['nl'] = LocaleConfiguration('nl') configuration.locales['en'] = LocaleConfiguration('en') self.site = Site(configuration)
async def test_load_gramps(self): with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') async with App(configuration) as app: gramps_file_path = Path( __file__).parent / 'assets' / 'minimal.gramps' load_gramps(app.ancestry, gramps_file_path)
async def test_places(self): configuration = Configuration(self._output_directory.name, 'https://ancestry.example.com') app = App(configuration) async with app: await generate(app) self.assert_betty_html(app, '/place/index.html') self.assert_betty_json(app, '/place/index.json', 'placeCollection')
def test_with_disabled_plugin(self): with TemporaryDirectory() as www_directory_path: environment = create_environment( Site(Configuration(www_directory_path, 'https://example.com'))) template = '{% if "' + TestPlugin.__module__ + \ '.TestPlugin" in plugins %}true{% else %}false{% endif %}' self.assertEquals('false', environment.from_string(template).render())
def test_with_comes_after_without_other_plugin(self): configuration = Configuration(**self._MINIMAL_CONFIGURATION_ARGS) configuration.plugins[ComesAfterNonConfigurablePluginPlugin] = {} sut = Site(configuration) event = TrackingEvent() sut.event_dispatcher.dispatch(event) self.assertEquals(1, len(event.tracker)) self.assertEquals(ComesAfterNonConfigurablePluginPlugin, type(event.tracker[0]))
async def test_extensions_addition_to_configuration(self) -> None: configuration = Configuration(**self._MINIMAL_CONFIGURATION_ARGS) async with App(configuration) as sut: # Get the extensions before making configuration changes to warm the cache. sut.extensions configuration.extensions.add( ExtensionConfiguration(NonConfigurableExtension)) self.assertIsInstance(sut.extensions[NonConfigurableExtension], NonConfigurableExtension)
async def test_extensions_removal_from_configuration(self) -> None: configuration = Configuration(**self._MINIMAL_CONFIGURATION_ARGS) configuration.extensions.add( ExtensionConfiguration(NonConfigurableExtension)) async with App(configuration) as sut: # Get the extensions before making configuration changes to warm the cache. sut.extensions del configuration.extensions[NonConfigurableExtension] self.assertNotIn(NonConfigurableExtension, sut.extensions)