OCA reporting engine fork for dev and update.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

213 lines
9.1 KiB

8 years ago
8 years ago
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2016 ACSONE SA/NV
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).).
  4. from base64 import b64decode
  5. import mock
  6. import os
  7. import pkg_resources
  8. import shutil
  9. import tempfile
  10. from contextlib import contextmanager
  11. from py3o.formats import Formats
  12. from odoo import tools
  13. from odoo.tests.common import TransactionCase
  14. from odoo.exceptions import ValidationError
  15. from ..models.py3o_report import TemplateNotFound
  16. from base64 import b64encode
  17. @contextmanager
  18. def temporary_copy(path):
  19. filname, ext = os.path.splitext(path)
  20. tmp_filename = tempfile.mktemp(suffix='.' + ext)
  21. try:
  22. shutil.copy2(path, tmp_filename)
  23. yield tmp_filename
  24. finally:
  25. os.unlink(tmp_filename)
  26. class TestReportPy3o(TransactionCase):
  27. def setUp(self):
  28. super(TestReportPy3o, self).setUp()
  29. self.report = self.env.ref("report_py3o.res_users_report_py3o")
  30. self.py3o_report = self.env['py3o.report'].create({
  31. 'ir_actions_report_xml_id': self.report.id})
  32. def test_no_local_fusion_without_fusion_server(self):
  33. self.assertTrue(self.report.py3o_is_local_fusion)
  34. with self.assertRaises(ValidationError) as e:
  35. self.report.py3o_is_local_fusion = False
  36. self.assertEqual(
  37. e.exception.name,
  38. "Can not use not native format in local fusion. "
  39. "Please specify a Fusion Server")
  40. def test_no_native_format_without_fusion_server(self):
  41. report = self.env.ref("report_py3o.res_users_report_py3o")
  42. formats = Formats()
  43. is_native = formats.get_format(report.py3o_filetype).native
  44. self.assertTrue(is_native)
  45. new_format = None
  46. for name in formats.get_known_format_names():
  47. format = formats.get_format(name)
  48. if not format.native:
  49. new_format = name
  50. break
  51. self.assertTrue(new_format)
  52. with self.assertRaises(ValidationError) as e:
  53. report.py3o_filetype = new_format
  54. self.assertEqual(
  55. e.exception.name,
  56. "Can not use not native format in local fusion. "
  57. "Please specify a Fusion Server")
  58. def test_required_py3_filetype(self):
  59. self.assertEqual(self.report.report_type, "py3o")
  60. with self.assertRaises(ValidationError) as e:
  61. self.report.py3o_filetype = False
  62. self.assertEqual(
  63. e.exception.name,
  64. "Field 'Output Format' is required for Py3O report")
  65. def test_reports(self):
  66. py3o_report = self.env['py3o.report']
  67. with mock.patch.object(
  68. py3o_report.__class__, '_create_single_report') as patched_pdf:
  69. result = tempfile.mktemp('.txt')
  70. with open(result, 'w') as fp:
  71. fp.write('dummy')
  72. patched_pdf.return_value = result
  73. # test the call the the create method inside our custom parser
  74. self.report.render_report(self.env.user.ids,
  75. self.report.report_name,
  76. {})
  77. self.assertEqual(1, patched_pdf.call_count)
  78. # generated files no more exists
  79. self.assertFalse(os.path.exists(result))
  80. res = self.report.render_report(
  81. self.env.user.ids, self.report.report_name, {})
  82. self.assertTrue(res)
  83. py3o_server = self.env['py3o.server'].create({"url": "http://dummy"})
  84. # check the call to the fusion server
  85. self.report.write({"py3o_filetype": "pdf",
  86. "py3o_server_id": py3o_server.id})
  87. with mock.patch('requests.post') as patched_post:
  88. magick_response = mock.MagicMock()
  89. magick_response.status_code = 200
  90. patched_post.return_value = magick_response
  91. magick_response.iter_content.return_value = "test result"
  92. res = self.report.render_report(
  93. self.env.user.ids, self.report.report_name, {})
  94. self.assertEqual(('test result', 'pdf'), res)
  95. def test_report_post_process(self):
  96. """
  97. By default the post_process method is in charge to save the
  98. generated report into an ir.attachment if requested.
  99. """
  100. report = self.env.ref("report_py3o.res_users_report_py3o")
  101. report.attachment = "object.name + '.txt'"
  102. py3o_server = self.env['py3o.server'].create({"url": "http://dummy"})
  103. # check the call to the fusion server
  104. report.write({"py3o_filetype": "pdf",
  105. "py3o_server_id": py3o_server.id})
  106. ir_attachment = self.env['ir.attachment']
  107. attachements = ir_attachment.search([(1, '=', 1)])
  108. with mock.patch('requests.post') as patched_post:
  109. magick_response = mock.MagicMock()
  110. magick_response.status_code = 200
  111. patched_post.return_value = magick_response
  112. magick_response.iter_content.return_value = "test result"
  113. res = report.render_report(
  114. self.env.user.ids, report.report_name, {})
  115. self.assertEqual(('test result', 'pdf'), res)
  116. attachements = ir_attachment.search([(1, '=', 1)]) - attachements
  117. self.assertEqual(1, len(attachements.ids))
  118. self.assertEqual(self.env.user.name + '.txt', attachements.name)
  119. self.assertEqual(self.env.user._name, attachements.res_model)
  120. self.assertEqual(self.env.user.id, attachements.res_id)
  121. self.assertEqual('test result', b64decode(attachements.datas))
  122. def test_report_template_configs(self):
  123. # the demo template is specified with a relative path in in the module
  124. # path
  125. tmpl_name = self.report.py3o_template_fallback
  126. flbk_filename = pkg_resources.resource_filename(
  127. "odoo.addons.%s" % self.report.module,
  128. tmpl_name)
  129. self.assertTrue(os.path.exists(flbk_filename))
  130. res = self.report.render_report(
  131. self.env.user.ids, self.report.report_name, {})
  132. self.assertTrue(res)
  133. # The generation fails if the tempalte is not found
  134. self.report.module = False
  135. with self.assertRaises(TemplateNotFound), self.env.cr.savepoint():
  136. self.report.render_report(
  137. self.env.user.ids, self.report.report_name, {})
  138. # the template can also be provided as an abspath if it's root path
  139. # is trusted
  140. self.report.py3o_template_fallback = flbk_filename
  141. with self.assertRaises(TemplateNotFound):
  142. self.report.render_report(
  143. self.env.user.ids, self.report.report_name, {})
  144. with temporary_copy(flbk_filename) as tmp_filename:
  145. self.report.py3o_template_fallback = tmp_filename
  146. tools.config.misc['report_py3o'] = {
  147. 'root_tmpl_path': os.path.dirname(tmp_filename)}
  148. res = self.report.render_report(
  149. self.env.user.ids, self.report.report_name, {})
  150. self.assertTrue(res)
  151. # the tempalte can also be provided as a binay field
  152. self.report.py3o_template_fallback = False
  153. with open(flbk_filename) as tmpl_file:
  154. tmpl_data = b64encode(tmpl_file.read())
  155. py3o_template = self.env['py3o.template'].create({
  156. 'name': 'test_template',
  157. 'py3o_template_data': tmpl_data,
  158. 'filetype': 'odt'})
  159. self.report.py3o_template_id = py3o_template
  160. self.report.py3o_template_fallback = flbk_filename
  161. res = self.report.render_report(
  162. self.env.user.ids, self.report.report_name, {})
  163. self.assertTrue(res)
  164. def test_report_template_fallback_validity(self):
  165. tmpl_name = self.report.py3o_template_fallback
  166. flbk_filename = pkg_resources.resource_filename(
  167. "odoo.addons.%s" % self.report.module,
  168. tmpl_name)
  169. # an exising file in a native format is a valid template if it's
  170. self.assertTrue(self.py3o_report._get_template_from_path(
  171. tmpl_name))
  172. self.report.module = None
  173. # a directory is not a valid template..
  174. self.assertFalse(self.py3o_report._get_template_from_path('/etc/'))
  175. self.assertFalse(self.py3o_report._get_template_from_path('.'))
  176. # an vaild template outside the root_tmpl_path is not a valid template
  177. # path
  178. # located in trusted directory
  179. self.report.py3o_template_fallback = flbk_filename
  180. self.assertFalse(self.py3o_report._get_template_from_path(
  181. flbk_filename))
  182. with temporary_copy(flbk_filename) as tmp_filename:
  183. self.assertTrue(self.py3o_report._get_template_from_path(
  184. tmp_filename))
  185. # check security
  186. self.assertFalse(self.py3o_report._get_template_from_path(
  187. 'rm -rf . & %s' % flbk_filename))
  188. # a file in a non native LibreOffice format is not a valid template
  189. with tempfile.NamedTemporaryFile(suffix='.toto')as f:
  190. self.assertFalse(self.py3o_report._get_template_from_path(
  191. f.name))
  192. # non exising files are not valid template
  193. self.assertFalse(self.py3o_report._get_template_from_path(
  194. '/etc/test.odt'))