157 lines
5.6 KiB
Python
157 lines
5.6 KiB
Python
# coding: utf-8
|
|
# passerelle - uniform access to multiple data sources and services
|
|
# Copyright (C) 2019 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
import io
|
|
import json
|
|
import uuid
|
|
import zipfile
|
|
|
|
import pytest
|
|
|
|
from passerelle.utils.zip import ZipTemplate, ZipTemplateDoesNotExist, ZipTemplateSyntaxError, ZipTemplateError
|
|
|
|
|
|
@pytest.fixture
|
|
def templates_path(tmpdir, settings):
|
|
path = tmpdir.mkdir('templates')
|
|
settings.TEMPLATES = settings.TEMPLATES[:]
|
|
settings.TEMPLATES[0] = settings.TEMPLATES[0].copy()
|
|
settings.TEMPLATES[0].setdefault('DIRS', [])
|
|
settings.TEMPLATES[0]['DIRS'].insert(0, str(path))
|
|
zip_templates_path = path.mkdir('zip_templates')
|
|
return zip_templates_path
|
|
|
|
|
|
@pytest.fixture
|
|
def tpl_builder(templates_path):
|
|
def make(name_template, template_parts=(), content_parts=()):
|
|
manifest_name = '%s.json' % uuid.uuid4().hex
|
|
manifest_path = templates_path / manifest_name
|
|
d = {
|
|
'name_template': name_template,
|
|
}
|
|
if template_parts or content_parts:
|
|
d['part_templates'] = []
|
|
for name_template, content in template_parts:
|
|
name = '%s.xml' % uuid.uuid4().hex
|
|
with (templates_path / name).open('w') as fd:
|
|
fd.write(content)
|
|
d['part_templates'].append({
|
|
'name_template': name_template,
|
|
'template_path': name,
|
|
})
|
|
for name_template, content in content_parts:
|
|
d['part_templates'].append({
|
|
'name_template': name_template,
|
|
'content_expression': content,
|
|
})
|
|
with manifest_path.open('w') as fd:
|
|
json.dump(d, fd)
|
|
return '%s/%s' % (templates_path.basename, manifest_name)
|
|
return make
|
|
|
|
|
|
@pytest.fixture
|
|
def dest(tmpdir):
|
|
return tmpdir.mkdir('dest')
|
|
|
|
|
|
def test_missing():
|
|
with pytest.raises(ZipTemplateDoesNotExist):
|
|
ZipTemplate('zip_templates/manifest1.json')
|
|
|
|
|
|
def test_invalid(templates_path):
|
|
path = templates_path / 'invalid-manifest.json'
|
|
with path.open(mode='w') as fd:
|
|
fd.write('{')
|
|
with pytest.raises(ZipTemplateError) as exc_info:
|
|
ZipTemplate(str(path))
|
|
assert 'invalid' in exc_info.value.args[0]
|
|
|
|
with path.open(mode='w') as fd:
|
|
fd.write('{}')
|
|
with pytest.raises(ZipTemplateError):
|
|
ZipTemplate(str(path))
|
|
assert 'invalid' in exc_info.value.args[0]
|
|
|
|
|
|
def test_syntax_error(tpl_builder, dest):
|
|
zip_template = ZipTemplate(tpl_builder('{{ name -{{ counter }}.zip'), ctx={'name': 'coucou', 'counter': 10})
|
|
with pytest.raises(ZipTemplateSyntaxError):
|
|
zip_template.render_to_path(dest)
|
|
|
|
zip_template = ZipTemplate(
|
|
tpl_builder(
|
|
'{{ name }}-{{ counter }}.zip',
|
|
template_parts=[('part1.xml', '{{ name {{ }}')]),
|
|
ctx={'name': 'coucou', 'counter': 10})
|
|
with pytest.raises(ZipTemplateSyntaxError):
|
|
zip_template.render_to_path(dest)
|
|
|
|
|
|
def test_no_parts(tpl_builder, dest):
|
|
z = ZipTemplate(tpl_builder('{{ name }}-{{ counter }}.zip'),
|
|
ctx={'name': 'coucou', 'counter': 10})
|
|
z.render_to_path(dest)
|
|
|
|
full_path = dest / 'coucou-10.zip'
|
|
with full_path.open('rb') as fd:
|
|
with zipfile.ZipFile(fd) as zi:
|
|
assert zi.namelist() == []
|
|
|
|
|
|
def test_with_parts(tpl_builder, dest):
|
|
z = ZipTemplate(
|
|
tpl_builder(
|
|
'{{ name }}-{{ counter }}.zip',
|
|
template_parts=[('{{ name }}-{{ counter }}-part1.xml',
|
|
'<?xml version="1.0"?><body>{{ bo_dy|lower }}</body>')],
|
|
content_parts=[('{{ name }}-{{ counter }}-dôc.xml', 'doc-content')],
|
|
),
|
|
ctx={'name': 'coucou', 'counter': 10, 'bo_dy': 'blabla', 'doc-content': '<a>Héllo World!</a>'})
|
|
z.render_to_path(dest)
|
|
for part in z.parts:
|
|
str(part)
|
|
|
|
full_path = dest / 'coucou-10.zip'
|
|
with full_path.open('rb') as fd:
|
|
with zipfile.ZipFile(fd) as zi:
|
|
assert zi.namelist() == ['coucou-10-part1.xml', 'coucou-10-dôc.xml']
|
|
assert zi.open('coucou-10-part1.xml').read().decode('utf-8') == '<?xml version="1.0"?><body>blabla</body>'
|
|
assert zi.open('coucou-10-dôc.xml').read().decode('utf-8') == '<a>Héllo World!</a>'
|
|
|
|
with io.BytesIO(z.render_to_bytes()) as fd:
|
|
with zipfile.ZipFile(fd) as zi:
|
|
assert zi.namelist() == ['coucou-10-part1.xml', 'coucou-10-dôc.xml']
|
|
assert zi.open('coucou-10-part1.xml').read().decode('utf-8') == '<?xml version="1.0"?><body>blabla</body>'
|
|
assert zi.open('coucou-10-dôc.xml').read().decode('utf-8') == '<a>Héllo World!</a>'
|
|
|
|
|
|
def test_xml_error(tpl_builder, dest):
|
|
z = ZipTemplate(
|
|
tpl_builder(
|
|
'rien.zip',
|
|
content_parts=[('rien.xml', 'doc-content')],
|
|
),
|
|
ctx={'doc-content': '<a>Héllo World!'})
|
|
with pytest.raises(ZipTemplateSyntaxError) as exc_info:
|
|
z.render_to_bytes()
|
|
assert 'XML syntax error' in exc_info.value.args[0]
|