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.

203 lines
8.0 KiB

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