def test_release_import_ocsid_absent(self): result = parse_app_metadata(self.min, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) self.importer.import_data('app', result['app'], None) app = App.objects.get(pk='news') self.assertEqual(None, app.ocsid)
def get_release_info(self, url: str, is_nightly: bool = False) -> Release: data = None with self.downloader.get_archive( url, self.config.download_root, self.config.download_max_timeout, self.config.download_max_redirects, self.config.download_max_size ) as download: xml, app_id, changelog = self.extractor.extract_app_metadata( download.filename) info = parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) info_app_id = info['app']['id'] if app_id != info_app_id: msg = 'Archive app folder is %s but info.xml reports id %s' \ % (app_id, info_app_id) raise InvalidAppDirectoryException(msg) release = info['app']['release'] info['app']['release']['is_nightly'] = is_nightly version = release['version'] release['changelog'] = changelog for code, value in changelog.items(): release['changelog'][code] = parse_changelog(value, version, is_nightly) with open(download.filename, 'rb') as f: data = f.read() return info, data
def test_parse_minimal(self): xml = self._get_test_xml('data/infoxmls/minimal.xml') result = parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) expected = {'app': { 'id': 'news', 'description': {'en': 'An RSS/Atom feed reader'}, 'name': {'en': 'News'}, 'admin_docs': None, 'developer_docs': None, 'user_docs': None, 'website': None, 'issue_tracker': None, 'screenshots': [], 'categories': [{'category': {'id': 'multimedia'}}], 'release': { 'databases': [], 'licenses': [{'license': {'id': 'agpl'}}], 'min_int_size': 32, 'php_extensions': [], 'php_max_version': '*', 'php_min_version': '*', 'platform_max_version': '*', 'platform_min_version': '9.0.0', 'shell_commands': [], 'version': '8.8.2' } }} self.assertDictEqual(expected, result)
def test_parse_pre_release(self): xml = self._get_contents('data/infoxmls/prerelease.xml') result = parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) version = result['app']['release']['version'] self.assertEqual('1.0.0-alpha.1', version)
def test_release_create_nighly(self): result = parse_app_metadata(self.min, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) result['app']['release']['is_nightly'] = True result['app']['website'] = 'https://website.com' self.importer.import_data('app', result['app'], None) app = App.objects.get(pk='news') self.assertEqual('https://website.com', app.website)
def test_release_update(self): result = parse_app_metadata(self.min, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) self.importer.import_release(result) result['app']['website'] = 'https://website.com' self.importer.import_release(result) app = App.objects.get(pk='news') self.assertEqual('https://website.com', app.website)
def test_parse_minimal_transform(self): xml = self._get_contents('data/infoxmls/transform.xml') result = parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) min_version = result['app']['release']['platform_min_version'] max_version = result['app']['release']['platform_max_version'] self.assertEqual('10.0.0', min_version) self.assertEqual('12.0.0', max_version)
def test_release_no_update_prerelease(self): result = parse_app_metadata(self.min, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) self.importer.import_data('app', result['app'], None) result['app']['website'] = 'https://website.com' result['app']['release']['version'] = '9.0.0-alpha' self.importer.import_data('app', result['app'], None) app = App.objects.get(pk='news') self.assertEqual('', app.website)
def test_parse_category_mapping_game(self): xml = self._get_contents('data/infoxmls/category_mapping_game.xml') result = parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) categories = result['app']['categories'] expected = [ {'category': {'id': 'tools'}}, ] self.assertListEqual(expected, categories)
def test_full(self): Database.objects.create(id='sqlite') Database.objects.create(id='pgsql') Database.objects.create(id='mysql') result = parse_app_metadata(self.full, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) self.importer.import_data('app', result['app'], None) app = App.objects.get(pk='news') # l10n app.set_current_language('en') self.assertEqual('News', app.name) self.assertEqual('An RSS/Atom feed reader', app.summary) self.assertEqual('#This is markdown', app.description) app.set_current_language('de') # fallback self.assertEqual('Nachrichten', app.name) self.assertEqual('https://help.nextcloud.com/t/news', app.discussion) self.assertEqual( 'Eine Nachrichten App, welche mit [RSS/Atom](' 'https://en.wikipedia.org/wiki/RSS) umgehen kann', app.description) release = app.releases.all()[0] extensions = release.php_extensions.all() databases = release.databases.all() self.assertEqual(3, databases.count()) self.assertEqual(4, extensions.count()) for db in databases: if db.id == 'sqlite': self.assertEqual('*', db.releasedependencies.get().version_spec) elif db.id == 'pgsql': self.assertEqual('>=9.4.0', db.releasedependencies.get().version_spec) elif db.id == 'mysql': self.assertEqual('>=5.5.0', db.releasedependencies.get().version_spec) for ex in extensions: if ex.id == 'libxml': self.assertEqual('>=2.7.8', ex.releasedependencies.get().version_spec) elif ex.id == 'curl': self.assertEqual('*', ex.releasedependencies.get().version_spec) elif ex.id == 'SimpleXML': self.assertEqual('*', ex.releasedependencies.get().version_spec) elif ex.id == 'iconv': self.assertEqual('*', ex.releasedependencies.get().version_spec)
def test_import_minimal(self): # check if translations are removed self.app.set_current_language('de') self.app.name = 'Should not exist' self.app.save() result = parse_app_metadata(self.min, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) self.importer.import_data('app', result['app'], None) app = App.objects.get(pk='news') self._assert_all_empty(app, ['user_docs', 'admin_docs', 'website', 'developer_docs']) # l10n app.set_current_language('en') self.assertEqual('News', app.name) self.assertEqual('An RSS/Atom feed reader', app.description) app.set_current_language('de') # fallback self.assertEqual('News', app.name) # authors self.assertEqual(1, app.authors.count()) self.assertEqual('Bernhard Posselt', app.authors.all()[0].name) # categories self.assertEqual(1, app.categories.count()) self.assertEqual('multimedia', app.categories.all()[0].id) self.assertEqual('https://github.com/nextcloud/news/issues', app.issue_tracker) self.assertEqual(0, app.screenshots.count()) self.assertEqual(0, Screenshot.objects.count()) release = app.releases.all()[0] self.assertEqual('8.8.2', release.version) self.assertEqual('>=9.0.0,<10.0.0', release.platform_version_spec) self.assertEqual('*', release.php_version_spec) self.assertEqual('>=9,<=9', release.raw_platform_version_spec) self.assertEqual('*', release.raw_php_version_spec) self.assertEqual(32, release.min_int_size) self._assert_all_empty(release, ['signature', 'download']) self.assertEqual(0, release.php_extensions.count()) self.assertEqual(0, release.databases.count()) self.assertEqual(0, release.shell_commands.count()) self.assertEqual(0, release.shell_commands.count()) self.assertEqual(1, release.licenses.count()) self.assertEqual('agpl', release.licenses.all()[0].id)
def test_validate_pre_11(self): xml = self._get_contents('data/infoxmls/9and10.xml') parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) xml = self._get_contents('data/infoxmls/11.xml') parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) xml = self._get_contents('data/infoxmls/9and10invalid.xml') with (self.assertRaises(InvalidAppMetadataXmlException)): parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt)
def test_parse_minimal(self): xml = self._get_contents('data/infoxmls/minimal.xml') result = parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) expected = {'app': { 'id': 'news', 'summary': {'en': 'An RSS/Atom feed reader'}, 'description': {'en': 'An RSS/Atom feed reader'}, 'authors': [{'author': { 'homepage': None, 'mail': None, 'name': 'Bernhard Posselt' }}], 'name': {'en': 'News'}, 'admin_docs': None, 'developer_docs': None, 'user_docs': None, 'website': None, 'issue_tracker': 'https://github.com/nextcloud/news/issues', 'screenshots': [], 'categories': [{'category': {'id': 'multimedia'}}], 'release': { 'databases': [], 'licenses': [{'license': {'id': 'agpl'}}], 'min_int_size': 32, 'php_extensions': [], 'php_max_version': '*', 'php_min_version': '*', 'raw_php_max_version': '*', 'raw_php_min_version': '*', 'platform_max_version': '10.0.0', 'platform_min_version': '9.0.0', 'raw_platform_max_version': '9', 'raw_platform_min_version': '9', 'shell_commands': [], 'version': '8.8.2', }, 'ocsid': None, }} self.assertDictEqual(expected, result)
def get_release_info(self, url: str) -> Dict: with self.downloader.get_archive( url, self.config.download_root, self.config.download_max_timeout, self.config.download_max_redirects, self.config.download_max_size ) as download: xml, archive_app_folder = self.extractor.extract_app_metadata( download.filename) info = parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) info_app_id = info['app']['id'] if archive_app_folder != info_app_id: msg = 'Archive app folder is %s but info.xml reports id %s' \ % (archive_app_folder, info_app_id) raise InvalidAppDirectoryException(msg) # generate sha256sum for archive with open(download.filename, 'rb') as f: checksum = sha256(f.read()).hexdigest() info['app']['release']['checksum'] = checksum return info
def test_entities(self): xml = self._get_test_xml('data/infoxmls/entities.xml') with (self.assertRaises(InvalidAppMetadataXmlException)): parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt)
def test_broken_xml(self): xml = self._get_test_xml('data/infoxmls/broken-xml.xml') with (self.assertRaises(APIException)): parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt)
def test_fixes_xml(self): xml = self._get_test_xml('data/infoxmls/news.xml') parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt)
def test_validate_english_summary(self): xml = self._get_test_xml('data/infoxmls/no_en_summary.xml') with (self.assertRaises(InvalidAppMetadataXmlException)): parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt)
def test_map_data(self): full = self._get_test_xml('data/infoxmls/full.xml') result = parse_app_metadata(full, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) expected = {'app': { 'id': 'news', 'admin_docs': 'https://github.com/owncloud/news#readme', 'categories': [ {'category': {'id': 'multimedia'}}, {'category': {'id': 'tools'}} ], 'description': { 'en': 'An RSS/Atom feed reader', 'de': 'Eine Nachrichten App, welche mit [RSS/Atom](' 'https://en.wikipedia.org/wiki/RSS) umgehen kann' }, 'developer_docs': 'https://github.com/owncloud/news/wiki#developer' '-documentation', 'user_docs': 'https://github.com/owncloud/news/wiki#user' '-documentation', 'website': 'https://github.com/owncloud/news', 'issue_tracker': 'https://github.com/owncloud/news/issues', 'name': {'de': 'Nachrichten', 'en': 'News'}, 'release': { 'databases': [ {'database': { 'id': 'pgsql', 'max_version': '*', 'min_version': '9.4.0' }}, {'database': { 'id': 'sqlite', 'max_version': '*', 'min_version': '*'}}, {'database': { 'id': 'mysql', 'max_version': '*', 'min_version': '5.5.0' }} ], 'licenses': [ {'license': {'id': 'agpl'}} ], 'min_int_size': 64, 'php_extensions': [ {'php_extension': { 'max_version': '*', 'min_version': '2.7.8', 'id': 'libxml' }}, {'php_extension': { 'max_version': '*', 'min_version': '*', 'id': 'curl' }}, {'php_extension': { 'max_version': '*', 'min_version': '*', 'id': 'SimpleXML' }}, {'php_extension': { 'max_version': '*', 'min_version': '*', 'id': 'iconv' }} ], 'php_max_version': '*', 'php_min_version': '5.6.0', 'platform_max_version': '9.2.0', 'platform_min_version': '9.0.0', 'shell_commands': [ {'shell_command': {'name': 'grep'}}, {'shell_command': {'name': 'ls'}} ], 'version': '8.8.2' }, 'screenshots': [ {'screenshot': {'url': 'https://example.com/1.png', 'ordering': 1}}, {'screenshot': {'url': 'https://example.com/2.jpg', 'ordering': 2}} ], }} self.assertDictEqual(expected, result)
def test_broken_xml(self): xml = self._get_contents('data/infoxmls/broken-xml.xml') with (self.assertRaises(ParseError)): parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt)
def test_bad_shell(self): xml = self._get_contents('data/infoxmls/badcommand.xml') with (self.assertRaises(InvalidAppMetadataXmlException)): parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt)
def test_parse_invalid_elements(self): xml = self._get_contents('data/infoxmls/invalid-elements.xml') with (self.assertRaises(InvalidAppMetadataXmlException)): parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt)
def test_parse_digit_id(self): xml = self._get_contents('data/infoxmls/digits.xml') result = parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) self.assertEqual('twofactor_u2f', result['app']['id'])
def test_parse_repair_jobs(self): xml = self._get_contents('data/infoxmls/repair-and-jobs.xml') parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt)
def test_map_data(self): full = self._get_contents('data/infoxmls/full.xml') result = parse_app_metadata(full, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt) expected = {'app': { 'id': 'news', 'admin_docs': 'https://github.com/owncloud/news#readme', 'categories': [ {'category': {'id': 'multimedia'}}, {'category': {'id': 'tools'}} ], 'authors': [ {'author': { 'homepage': 'http://example.com', 'mail': '*****@*****.**', 'name': 'Bernhard Posselt' }}, {'author': { 'homepage': None, 'mail': None, 'name': 'Alessandro Cosentino' }}, {'author': { 'homepage': None, 'mail': None, 'name': 'Jan-Christoph Borchardt' }} ], 'summary': { 'en': 'An RSS/Atom feed reader', 'de': 'An RSS/Atom feed reader', }, 'description': { 'en': '#This is markdown', 'de': 'Eine Nachrichten App, welche mit [RSS/Atom](' 'https://en.wikipedia.org/wiki/RSS) umgehen kann' }, 'developer_docs': 'https://github.com/owncloud/news/wiki#developer' '-documentation', 'user_docs': 'https://github.com/owncloud/news/wiki#user' '-documentation', 'website': 'https://github.com/owncloud/news', 'issue_tracker': 'https://github.com/owncloud/news/issues', 'name': {'de': 'Nachrichten', 'en': 'News'}, 'release': { 'databases': [ {'database': { 'id': 'pgsql', 'max_version': '*', 'min_version': '9.4.0', 'raw_max_version': '*', 'raw_min_version': '9.4', }}, {'database': { 'id': 'sqlite', 'max_version': '*', 'min_version': '*', 'raw_max_version': '*', 'raw_min_version': '*', }}, {'database': { 'id': 'mysql', 'max_version': '*', 'min_version': '5.5.0', 'raw_max_version': '*', 'raw_min_version': '5.5', }} ], 'licenses': [ {'license': {'id': 'agpl'}} ], 'min_int_size': 64, 'php_extensions': [ {'php_extension': { 'max_version': '*', 'min_version': '2.7.8', 'raw_max_version': '*', 'raw_min_version': '2.7.8', 'id': 'libxml' }}, {'php_extension': { 'max_version': '*', 'min_version': '*', 'raw_max_version': '*', 'raw_min_version': '*', 'id': 'curl' }}, {'php_extension': { 'max_version': '*', 'min_version': '*', 'raw_max_version': '*', 'raw_min_version': '*', 'id': 'SimpleXML' }}, {'php_extension': { 'max_version': '*', 'min_version': '*', 'raw_max_version': '*', 'raw_min_version': '*', 'id': 'iconv' }} ], 'php_max_version': '*', 'php_min_version': '5.6.0', 'raw_php_max_version': '*', 'raw_php_min_version': '5.6', 'platform_max_version': '11.0.0', 'platform_min_version': '9.0.0', 'raw_platform_max_version': '10', 'raw_platform_min_version': '9', 'shell_commands': [ {'shell_command': {'name': 'grep'}}, {'shell_command': {'name': 'ls'}} ], 'version': '8.8.2', }, 'screenshots': [ {'screenshot': {'url': 'https://example.com/1.png', 'small_thumbnail': None, 'ordering': 1}}, {'screenshot': {'url': 'https://example.com/2.jpg', 'small_thumbnail': None, 'ordering': 2}} ], 'ocsid': None, }} self.assertDictEqual(expected, result)
def test_validate_english_description(self): xml = self._get_contents('data/infoxmls/no_en_description.xml') with (self.assertRaises(InvalidAppMetadataXmlException)): parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt)