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.

237 lines
9.4 KiB

  1. # Copyright 2017 LasLabs Inc.
  2. # Copyright 2018 ACSONE SA/NV.
  3. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
  4. import os
  5. import tempfile
  6. import mock
  7. import odoo
  8. from odoo.modules import get_module_path
  9. from odoo.tests 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. @odoo.tests.tagged('post_install', '-at_install')
  68. class TestModuleAfterInstall(TransactionCase):
  69. def setUp(self):
  70. super(TestModuleAfterInstall, self).setUp()
  71. Imm = self.env['ir.module.module']
  72. self.own_module = Imm.search([('name', '=', MODULE_NAME)])
  73. self.base_module = Imm.search([('name', '=', 'base')])
  74. def test_get_modules_partially_installed(self):
  75. Imm = self.env['ir.module.module']
  76. self.assertTrue(
  77. self.own_module not in Imm._get_modules_partially_installed())
  78. self.own_module.button_upgrade()
  79. self.assertTrue(
  80. self.own_module in Imm._get_modules_partially_installed())
  81. self.own_module.button_upgrade_cancel()
  82. self.assertTrue(
  83. self.own_module not in Imm._get_modules_partially_installed())
  84. def test_upgrade_changed_checksum(self):
  85. Imm = self.env['ir.module.module']
  86. Bmu = self.env['base.module.upgrade']
  87. # check modules are in installed state
  88. installed_modules = Imm.search([('state', '=', 'installed')])
  89. self.assertTrue(self.own_module in installed_modules)
  90. self.assertTrue(self.base_module in installed_modules)
  91. self.assertTrue(len(installed_modules) > 2)
  92. # change the checksum of 'base'
  93. Imm._save_installed_checksums()
  94. saved_checksums = Imm._get_saved_checksums()
  95. saved_checksums['base'] = False
  96. Imm._save_checksums(saved_checksums)
  97. changed_modules = Imm._get_modules_with_changed_checksum()
  98. self.assertEqual(len(changed_modules), 1)
  99. self.assertTrue(self.base_module in changed_modules)
  100. def upgrade_module_mock(self_model):
  101. upgrade_module_mock.call_count += 1
  102. # since we are upgrading base, all installed module
  103. # must have been marked to upgrade at this stage
  104. self.assertEqual(self.base_module.state, 'to upgrade')
  105. self.assertEqual(self.own_module.state, 'to upgrade')
  106. installed_modules.write({'state': 'installed'})
  107. upgrade_module_mock.call_count = 0
  108. # upgrade_changed_checksum commits, so mock that
  109. with mock.patch.object(self.env.cr, 'commit'):
  110. # we simulate an install by setting module states
  111. Bmu._patch_method('upgrade_module', upgrade_module_mock)
  112. try:
  113. Imm.upgrade_changed_checksum()
  114. self.assertEqual(upgrade_module_mock.call_count, 1)
  115. self.assertEqual(self.base_module.state, 'installed')
  116. self.assertEqual(self.own_module.state, 'installed')
  117. saved_checksums = Imm._get_saved_checksums()
  118. self.assertTrue(saved_checksums['base'])
  119. self.assertTrue(saved_checksums[MODULE_NAME])
  120. finally:
  121. Bmu._revert_method('upgrade_module')
  122. def test_incomplete_upgrade(self):
  123. Imm = self.env['ir.module.module']
  124. Bmu = self.env['base.module.upgrade']
  125. installed_modules = Imm.search([('state', '=', 'installed')])
  126. # change the checksum of 'base'
  127. Imm._save_installed_checksums()
  128. saved_checksums = Imm._get_saved_checksums()
  129. saved_checksums['base'] = False
  130. Imm._save_checksums(saved_checksums)
  131. def upgrade_module_mock(self_model):
  132. upgrade_module_mock.call_count += 1
  133. # since we are upgrading base, all installed module
  134. # must have been marked to upgrade at this stage
  135. self.assertEqual(self.base_module.state, 'to upgrade')
  136. self.assertEqual(self.own_module.state, 'to upgrade')
  137. installed_modules.write({'state': 'installed'})
  138. # simulate partial upgrade
  139. self.own_module.write({'state': 'to upgrade'})
  140. upgrade_module_mock.call_count = 0
  141. # upgrade_changed_checksum commits, so mock that
  142. with mock.patch.object(self.env.cr, 'commit'):
  143. # we simulate an install by setting module states
  144. Bmu._patch_method('upgrade_module', upgrade_module_mock)
  145. try:
  146. with self.assertRaises(IncompleteUpgradeError):
  147. Imm.upgrade_changed_checksum()
  148. self.assertEqual(upgrade_module_mock.call_count, 1)
  149. finally:
  150. Bmu._revert_method('upgrade_module')
  151. def test_incomplete_upgrade_no_checkusm(self):
  152. Imm = self.env['ir.module.module']
  153. Bmu = self.env['base.module.upgrade']
  154. installed_modules = Imm.search(
  155. [('state', '=', 'installed')])
  156. # change the checksum of 'base'
  157. Imm._save_installed_checksums()
  158. saved_checksums = Imm._get_saved_checksums()
  159. Imm._save_checksums(saved_checksums)
  160. self.base_module.write({'state': 'to upgrade'})
  161. def upgrade_module_mock(self_model):
  162. upgrade_module_mock.call_count += 1
  163. # since we are upgrading base, all installed module
  164. # must have been marked to upgrade at this stage
  165. self.assertEqual(self.base_module.state, 'to upgrade')
  166. self.assertEqual(self.own_module.state, 'installed')
  167. installed_modules.write({'state': 'installed'})
  168. upgrade_module_mock.call_count = 0
  169. # upgrade_changed_checksum commits, so mock that
  170. with mock.patch.object(self.env.cr, 'commit'):
  171. # we simulate an install by setting module states
  172. Bmu._patch_method('upgrade_module',
  173. upgrade_module_mock)
  174. # got just other modules to_upgrade and no checksum ones
  175. try:
  176. Imm.upgrade_changed_checksum()
  177. self.assertEqual(upgrade_module_mock.call_count, 1)
  178. finally:
  179. Bmu._revert_method('upgrade_module')
  180. def test_nothing_to_upgrade(self):
  181. Imm = self.env['ir.module.module']
  182. Bmu = self.env['base.module.upgrade']
  183. Imm._save_installed_checksums()
  184. def upgrade_module_mock(self_model):
  185. upgrade_module_mock.call_count += 1
  186. upgrade_module_mock.call_count = 0
  187. # upgrade_changed_checksum commits, so mock that
  188. with mock.patch.object(self.env.cr, 'commit'):
  189. # we simulate an install by setting module states
  190. Bmu._patch_method('upgrade_module', upgrade_module_mock)
  191. try:
  192. Imm.upgrade_changed_checksum()
  193. self.assertEqual(upgrade_module_mock.call_count, 0)
  194. finally:
  195. Bmu._revert_method('upgrade_module')