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.

238 lines
9.4 KiB

  1. # Copyright 2017 LasLabs Inc.
  2. # Copyright 2018 ACSONE SA/NV.
  3. # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
  4. import os
  5. import tempfile
  6. import mock
  7. from odoo.modules import get_module_path
  8. from odoo.tests import common
  9. from odoo.tests.common import TransactionCase
  10. from ..addon_hash import addon_hash
  11. from ..models.module import IncompleteUpgradeError, DEFAULT_EXCLUDE_PATTERNS
  12. MODULE_NAME = 'module_auto_update'
  13. class TestModule(TransactionCase):
  14. def setUp(self):
  15. super(TestModule, self).setUp()
  16. self.own_module = self.env['ir.module.module'].search([
  17. ('name', '=', MODULE_NAME),
  18. ])
  19. self.own_dir_path = get_module_path(MODULE_NAME)
  20. keep_langs = self.env['res.lang'].search([]).mapped('code')
  21. self.own_checksum = addon_hash(
  22. self.own_dir_path,
  23. exclude_patterns=DEFAULT_EXCLUDE_PATTERNS.split(','),
  24. keep_langs=keep_langs,
  25. )
  26. self.own_writeable = os.access(self.own_dir_path, os.W_OK)
  27. def test_compute_checksum_dir(self):
  28. """It should compute the directory's SHA-1 hash"""
  29. self.assertEqual(
  30. self.own_module._get_checksum_dir(), self.own_checksum,
  31. 'Module directory checksum not computed properly',
  32. )
  33. def test_compute_checksum_dir_ignore_excluded(self):
  34. """It should exclude .pyc/.pyo extensions from checksum
  35. calculations"""
  36. if not self.own_writeable:
  37. self.skipTest("Own directory not writeable")
  38. with tempfile.NamedTemporaryFile(suffix='.pyc', dir=self.own_dir_path):
  39. self.assertEqual(
  40. self.own_module._get_checksum_dir(), self.own_checksum,
  41. 'SHA1 checksum does not ignore excluded extensions',
  42. )
  43. def test_compute_checksum_dir_recomputes_when_file_added(self):
  44. """It should return a different value when a non-.pyc/.pyo file is
  45. added to the module directory"""
  46. if not self.own_writeable:
  47. self.skipTest("Own directory not writeable")
  48. with tempfile.NamedTemporaryFile(suffix='.py', dir=self.own_dir_path):
  49. self.assertNotEqual(
  50. self.own_module._get_checksum_dir(), self.own_checksum,
  51. 'SHA1 checksum not recomputed',
  52. )
  53. def test_saved_checksums(self):
  54. Imm = self.env['ir.module.module']
  55. base_module = Imm.search([('name', '=', 'base')])
  56. self.assertEqual(base_module.state, 'installed')
  57. self.assertFalse(Imm._get_saved_checksums())
  58. Imm._save_installed_checksums()
  59. saved_checksums = Imm._get_saved_checksums()
  60. self.assertTrue(saved_checksums)
  61. self.assertTrue(saved_checksums['base'])
  62. def test_get_modules_with_changed_checksum(self):
  63. Imm = self.env['ir.module.module']
  64. self.assertTrue(Imm._get_modules_with_changed_checksum())
  65. Imm._save_installed_checksums()
  66. self.assertFalse(Imm._get_modules_with_changed_checksum())
  67. @common.at_install(False)
  68. @common.post_install(True)
  69. class TestModuleAfterInstall(TransactionCase):
  70. def setUp(self):
  71. super(TestModuleAfterInstall, self).setUp()
  72. Imm = self.env['ir.module.module']
  73. self.own_module = Imm.search([('name', '=', MODULE_NAME)])
  74. self.base_module = Imm.search([('name', '=', 'base')])
  75. def test_get_modules_partially_installed(self):
  76. Imm = self.env['ir.module.module']
  77. self.assertTrue(
  78. self.own_module not in Imm._get_modules_partially_installed())
  79. self.own_module.button_upgrade()
  80. self.assertTrue(
  81. self.own_module in Imm._get_modules_partially_installed())
  82. self.own_module.button_upgrade_cancel()
  83. self.assertTrue(
  84. self.own_module not in Imm._get_modules_partially_installed())
  85. def test_upgrade_changed_checksum(self):
  86. Imm = self.env['ir.module.module']
  87. Bmu = self.env['base.module.upgrade']
  88. # check modules are in installed state
  89. installed_modules = Imm.search([('state', '=', 'installed')])
  90. self.assertTrue(self.own_module in installed_modules)
  91. self.assertTrue(self.base_module in installed_modules)
  92. self.assertTrue(len(installed_modules) > 2)
  93. # change the checksum of 'base'
  94. Imm._save_installed_checksums()
  95. saved_checksums = Imm._get_saved_checksums()
  96. saved_checksums['base'] = False
  97. Imm._save_checksums(saved_checksums)
  98. changed_modules = Imm._get_modules_with_changed_checksum()
  99. self.assertEqual(len(changed_modules), 1)
  100. self.assertTrue(self.base_module in changed_modules)
  101. def upgrade_module_mock(self_model):
  102. upgrade_module_mock.call_count += 1
  103. # since we are upgrading base, all installed module
  104. # must have been marked to upgrade at this stage
  105. self.assertEqual(self.base_module.state, 'to upgrade')
  106. self.assertEqual(self.own_module.state, 'to upgrade')
  107. installed_modules.write({'state': 'installed'})
  108. upgrade_module_mock.call_count = 0
  109. # upgrade_changed_checksum commits, so mock that
  110. with mock.patch.object(self.env.cr, 'commit'):
  111. # we simulate an install by setting module states
  112. Bmu._patch_method('upgrade_module', upgrade_module_mock)
  113. try:
  114. Imm.upgrade_changed_checksum()
  115. self.assertEqual(upgrade_module_mock.call_count, 1)
  116. self.assertEqual(self.base_module.state, 'installed')
  117. self.assertEqual(self.own_module.state, 'installed')
  118. saved_checksums = Imm._get_saved_checksums()
  119. self.assertTrue(saved_checksums['base'])
  120. self.assertTrue(saved_checksums[MODULE_NAME])
  121. finally:
  122. Bmu._revert_method('upgrade_module')
  123. def test_incomplete_upgrade(self):
  124. Imm = self.env['ir.module.module']
  125. Bmu = self.env['base.module.upgrade']
  126. installed_modules = Imm.search([('state', '=', 'installed')])
  127. # change the checksum of 'base'
  128. Imm._save_installed_checksums()
  129. saved_checksums = Imm._get_saved_checksums()
  130. saved_checksums['base'] = False
  131. Imm._save_checksums(saved_checksums)
  132. def upgrade_module_mock(self_model):
  133. upgrade_module_mock.call_count += 1
  134. # since we are upgrading base, all installed module
  135. # must have been marked to upgrade at this stage
  136. self.assertEqual(self.base_module.state, 'to upgrade')
  137. self.assertEqual(self.own_module.state, 'to upgrade')
  138. installed_modules.write({'state': 'installed'})
  139. # simulate partial upgrade
  140. self.own_module.write({'state': 'to upgrade'})
  141. upgrade_module_mock.call_count = 0
  142. # upgrade_changed_checksum commits, so mock that
  143. with mock.patch.object(self.env.cr, 'commit'):
  144. # we simulate an install by setting module states
  145. Bmu._patch_method('upgrade_module', upgrade_module_mock)
  146. try:
  147. with self.assertRaises(IncompleteUpgradeError):
  148. Imm.upgrade_changed_checksum()
  149. self.assertEqual(upgrade_module_mock.call_count, 1)
  150. finally:
  151. Bmu._revert_method('upgrade_module')
  152. def test_incomplete_upgrade_no_checkusm(self):
  153. Imm = self.env['ir.module.module']
  154. Bmu = self.env['base.module.upgrade']
  155. installed_modules = Imm.search(
  156. [('state', '=', 'installed')])
  157. # change the checksum of 'base'
  158. Imm._save_installed_checksums()
  159. saved_checksums = Imm._get_saved_checksums()
  160. Imm._save_checksums(saved_checksums)
  161. self.base_module.write({'state': 'to upgrade'})
  162. def upgrade_module_mock(self_model):
  163. upgrade_module_mock.call_count += 1
  164. # since we are upgrading base, all installed module
  165. # must have been marked to upgrade at this stage
  166. self.assertEqual(self.base_module.state, 'to upgrade')
  167. self.assertEqual(self.own_module.state, 'installed')
  168. installed_modules.write({'state': 'installed'})
  169. upgrade_module_mock.call_count = 0
  170. # upgrade_changed_checksum commits, so mock that
  171. with mock.patch.object(self.env.cr, 'commit'):
  172. # we simulate an install by setting module states
  173. Bmu._patch_method('upgrade_module',
  174. upgrade_module_mock)
  175. # got just other modules to_upgrade and no checksum ones
  176. try:
  177. Imm.upgrade_changed_checksum()
  178. self.assertEqual(upgrade_module_mock.call_count, 1)
  179. finally:
  180. Bmu._revert_method('upgrade_module')
  181. def test_nothing_to_upgrade(self):
  182. Imm = self.env['ir.module.module']
  183. Bmu = self.env['base.module.upgrade']
  184. Imm._save_installed_checksums()
  185. def upgrade_module_mock(self_model):
  186. upgrade_module_mock.call_count += 1
  187. upgrade_module_mock.call_count = 0
  188. # upgrade_changed_checksum commits, so mock that
  189. with mock.patch.object(self.env.cr, 'commit'):
  190. # we simulate an install by setting module states
  191. Bmu._patch_method('upgrade_module', upgrade_module_mock)
  192. try:
  193. Imm.upgrade_changed_checksum()
  194. self.assertEqual(upgrade_module_mock.call_count, 0)
  195. finally:
  196. Bmu._revert_method('upgrade_module')