OpenStack Image Management (Glance)
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.

test_manage.py 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. # Copyright 2014 Rackspace Hosting
  2. # All Rights Reserved.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. from __future__ import absolute_import
  16. import fixtures
  17. import mock
  18. from six.moves import StringIO
  19. from glance.cmd import manage
  20. from glance.common import exception
  21. from glance.db.sqlalchemy import alembic_migrations
  22. from glance.db.sqlalchemy import api as db_api
  23. from glance.db.sqlalchemy import metadata as db_metadata
  24. from glance.tests import utils as test_utils
  25. from sqlalchemy.engine.url import make_url as sqlalchemy_make_url
  26. class TestManageBase(test_utils.BaseTestCase):
  27. def setUp(self):
  28. super(TestManageBase, self).setUp()
  29. def clear_conf():
  30. manage.CONF.reset()
  31. manage.CONF.unregister_opt(manage.command_opt)
  32. clear_conf()
  33. self.addCleanup(clear_conf)
  34. self.useFixture(fixtures.MonkeyPatch(
  35. 'oslo_log.log.setup', lambda product_name, version='test': None))
  36. patcher = mock.patch('glance.db.sqlalchemy.api.get_engine')
  37. patcher.start()
  38. self.addCleanup(patcher.stop)
  39. def _main_test_helper(self, argv, func_name=None, *exp_args, **exp_kwargs):
  40. self.useFixture(fixtures.MonkeyPatch('sys.argv', argv))
  41. manage.main()
  42. func_name.assert_called_once_with(*exp_args, **exp_kwargs)
  43. class TestLegacyManage(TestManageBase):
  44. @mock.patch.object(manage.DbCommands, 'version')
  45. def test_legacy_db_version(self, db_upgrade):
  46. self._main_test_helper(['glance.cmd.manage', 'db_version'],
  47. manage.DbCommands.version)
  48. @mock.patch.object(manage.DbCommands, 'sync')
  49. def test_legacy_db_sync(self, db_sync):
  50. self._main_test_helper(['glance.cmd.manage', 'db_sync'],
  51. manage.DbCommands.sync, None)
  52. @mock.patch.object(manage.DbCommands, 'upgrade')
  53. def test_legacy_db_upgrade(self, db_upgrade):
  54. self._main_test_helper(['glance.cmd.manage', 'db_upgrade'],
  55. manage.DbCommands.upgrade, None)
  56. @mock.patch.object(manage.DbCommands, 'version_control')
  57. def test_legacy_db_version_control(self, db_version_control):
  58. self._main_test_helper(['glance.cmd.manage', 'db_version_control'],
  59. manage.DbCommands.version_control, None)
  60. @mock.patch.object(manage.DbCommands, 'sync')
  61. def test_legacy_db_sync_version(self, db_sync):
  62. self._main_test_helper(['glance.cmd.manage', 'db_sync', 'liberty'],
  63. manage.DbCommands.sync, 'liberty')
  64. @mock.patch.object(manage.DbCommands, 'upgrade')
  65. def test_legacy_db_upgrade_version(self, db_upgrade):
  66. self._main_test_helper(['glance.cmd.manage', 'db_upgrade', 'liberty'],
  67. manage.DbCommands.upgrade, 'liberty')
  68. @mock.patch.object(manage.DbCommands, 'expand')
  69. def test_legacy_db_expand(self, db_expand):
  70. self._main_test_helper(['glance.cmd.manage', 'db_expand'],
  71. manage.DbCommands.expand)
  72. @mock.patch.object(manage.DbCommands, 'migrate')
  73. def test_legacy_db_migrate(self, db_migrate):
  74. self._main_test_helper(['glance.cmd.manage', 'db_migrate'],
  75. manage.DbCommands.migrate)
  76. @mock.patch.object(manage.DbCommands, 'contract')
  77. def test_legacy_db_contract(self, db_contract):
  78. self._main_test_helper(['glance.cmd.manage', 'db_contract'],
  79. manage.DbCommands.contract)
  80. def test_db_metadefs_unload(self):
  81. db_metadata.db_unload_metadefs = mock.Mock()
  82. self._main_test_helper(['glance.cmd.manage', 'db_unload_metadefs'],
  83. db_metadata.db_unload_metadefs,
  84. db_api.get_engine())
  85. def test_db_metadefs_load(self):
  86. db_metadata.db_load_metadefs = mock.Mock()
  87. self._main_test_helper(['glance.cmd.manage', 'db_load_metadefs'],
  88. db_metadata.db_load_metadefs,
  89. db_api.get_engine(),
  90. None, None, None, None)
  91. def test_db_metadefs_load_with_specified_path(self):
  92. db_metadata.db_load_metadefs = mock.Mock()
  93. self._main_test_helper(['glance.cmd.manage', 'db_load_metadefs',
  94. '/mock/'],
  95. db_metadata.db_load_metadefs,
  96. db_api.get_engine(),
  97. '/mock/', None, None, None)
  98. def test_db_metadefs_load_from_path_merge(self):
  99. db_metadata.db_load_metadefs = mock.Mock()
  100. self._main_test_helper(['glance.cmd.manage', 'db_load_metadefs',
  101. '/mock/', 'True'],
  102. db_metadata.db_load_metadefs,
  103. db_api.get_engine(),
  104. '/mock/', 'True', None, None)
  105. def test_db_metadefs_load_from_merge_and_prefer_new(self):
  106. db_metadata.db_load_metadefs = mock.Mock()
  107. self._main_test_helper(['glance.cmd.manage', 'db_load_metadefs',
  108. '/mock/', 'True', 'True'],
  109. db_metadata.db_load_metadefs,
  110. db_api.get_engine(),
  111. '/mock/', 'True', 'True', None)
  112. def test_db_metadefs_load_from_merge_and_prefer_new_and_overwrite(self):
  113. db_metadata.db_load_metadefs = mock.Mock()
  114. self._main_test_helper(['glance.cmd.manage', 'db_load_metadefs',
  115. '/mock/', 'True', 'True', 'True'],
  116. db_metadata.db_load_metadefs,
  117. db_api.get_engine(),
  118. '/mock/', 'True', 'True', 'True')
  119. def test_db_metadefs_export(self):
  120. db_metadata.db_export_metadefs = mock.Mock()
  121. self._main_test_helper(['glance.cmd.manage', 'db_export_metadefs'],
  122. db_metadata.db_export_metadefs,
  123. db_api.get_engine(),
  124. None)
  125. def test_db_metadefs_export_with_specified_path(self):
  126. db_metadata.db_export_metadefs = mock.Mock()
  127. self._main_test_helper(['glance.cmd.manage', 'db_export_metadefs',
  128. '/mock/'],
  129. db_metadata.db_export_metadefs,
  130. db_api.get_engine(),
  131. '/mock/')
  132. class TestManage(TestManageBase):
  133. def setUp(self):
  134. super(TestManage, self).setUp()
  135. self.db = manage.DbCommands()
  136. self.output = StringIO()
  137. self.useFixture(fixtures.MonkeyPatch('sys.stdout', self.output))
  138. def test_db_complex_password(self):
  139. engine = mock.Mock()
  140. # See comments in get_alembic_config; make an engine url with
  141. # password characters that will be escaped, to ensure the
  142. # resulting value makes it into alembic unaltered.
  143. engine.url = sqlalchemy_make_url(
  144. 'mysql+pymysql://username:pw@%/!#$()@host:1234/dbname')
  145. alembic_config = alembic_migrations.get_alembic_config(engine)
  146. self.assertEqual(str(engine.url),
  147. alembic_config.get_main_option('sqlalchemy.url'))
  148. @mock.patch('glance.db.sqlalchemy.api.get_engine')
  149. @mock.patch(
  150. 'glance.db.sqlalchemy.alembic_migrations.data_migrations.'
  151. 'has_pending_migrations')
  152. @mock.patch(
  153. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  154. @mock.patch(
  155. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  156. def test_db_check_result(self, mock_get_alembic_branch_head,
  157. mock_get_current_alembic_heads,
  158. mock_has_pending_migrations,
  159. get_mock_engine):
  160. get_mock_engine.return_value = mock.Mock()
  161. engine = get_mock_engine.return_value
  162. engine.engine.name = 'postgresql'
  163. exit = self.assertRaises(SystemExit, self.db.check)
  164. self.assertIn('Rolling upgrades are currently supported only for '
  165. 'MySQL and Sqlite', exit.code)
  166. engine = get_mock_engine.return_value
  167. engine.engine.name = 'mysql'
  168. mock_get_current_alembic_heads.return_value = ['ocata_contract01']
  169. mock_get_alembic_branch_head.return_value = 'pike_expand01'
  170. exit = self.assertRaises(SystemExit, self.db.check)
  171. self.assertEqual(3, exit.code)
  172. self.assertIn('Your database is not up to date. '
  173. 'Your first step is to run `glance-manage db expand`.',
  174. self.output.getvalue())
  175. mock_get_current_alembic_heads.return_value = ['pike_expand01']
  176. mock_get_alembic_branch_head.side_effect = ['pike_expand01', None]
  177. mock_has_pending_migrations.return_value = [mock.Mock()]
  178. exit = self.assertRaises(SystemExit, self.db.check)
  179. self.assertEqual(4, exit.code)
  180. self.assertIn('Your database is not up to date. '
  181. 'Your next step is to run `glance-manage db migrate`.',
  182. self.output.getvalue())
  183. mock_get_current_alembic_heads.return_value = ['pike_expand01']
  184. mock_get_alembic_branch_head.side_effect = ['pike_expand01',
  185. 'pike_contract01']
  186. mock_has_pending_migrations.return_value = None
  187. exit = self.assertRaises(SystemExit, self.db.check)
  188. self.assertEqual(5, exit.code)
  189. self.assertIn('Your database is not up to date. '
  190. 'Your next step is to run `glance-manage db contract`.',
  191. self.output.getvalue())
  192. mock_get_current_alembic_heads.return_value = ['pike_contract01']
  193. mock_get_alembic_branch_head.side_effect = ['pike_expand01',
  194. 'pike_contract01']
  195. mock_has_pending_migrations.return_value = None
  196. self.assertRaises(SystemExit, self.db.check)
  197. self.assertIn('Database is up to date. No upgrades needed.',
  198. self.output.getvalue())
  199. @mock.patch(
  200. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  201. @mock.patch(
  202. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  203. @mock.patch.object(manage.DbCommands, 'expand')
  204. @mock.patch.object(manage.DbCommands, 'migrate')
  205. @mock.patch.object(manage.DbCommands, 'contract')
  206. def test_sync(self, mock_contract, mock_migrate, mock_expand,
  207. mock_get_alembic_branch_head,
  208. mock_get_current_alembic_heads):
  209. mock_get_current_alembic_heads.return_value = ['ocata_contract01']
  210. mock_get_alembic_branch_head.return_value = ['pike_contract01']
  211. self.db.sync()
  212. mock_expand.assert_called_once_with(online_migration=False)
  213. mock_migrate.assert_called_once_with(online_migration=False)
  214. mock_contract.assert_called_once_with(online_migration=False)
  215. self.assertIn('Database is synced successfully.',
  216. self.output.getvalue())
  217. @mock.patch(
  218. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  219. @mock.patch(
  220. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  221. @mock.patch('glance.db.sqlalchemy.alembic_migrations.'
  222. 'place_database_under_alembic_control')
  223. @mock.patch('alembic.command.upgrade')
  224. def test_sync_db_is_already_sync(self, mock_upgrade,
  225. mock_db_under_alembic_control,
  226. mock_get_alembic_branch_head,
  227. mock_get_current_alembic_heads):
  228. mock_get_current_alembic_heads.return_value = ['pike_contract01']
  229. mock_get_alembic_branch_head.return_value = ['pike_contract01']
  230. self.assertRaises(SystemExit, self.db.sync)
  231. @mock.patch(
  232. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  233. @mock.patch(
  234. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  235. @mock.patch.object(manage.DbCommands, '_validate_engine')
  236. @mock.patch.object(manage.DbCommands, 'expand')
  237. def test_sync_failed_to_sync(self, mock_expand, mock_validate_engine,
  238. mock_get_alembic_branch_head,
  239. mock_get_current_alembic_heads):
  240. engine = mock_validate_engine.return_value
  241. engine.engine.name = 'mysql'
  242. mock_get_current_alembic_heads.return_value = ['ocata_contract01']
  243. mock_get_alembic_branch_head.side_effect = ['pike_contract01', '']
  244. mock_expand.side_effect = exception.GlanceException
  245. exit = self.assertRaises(SystemExit, self.db.sync)
  246. self.assertIn('Failed to sync database: ERROR:', exit.code)
  247. @mock.patch(
  248. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  249. @mock.patch(
  250. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  251. @mock.patch.object(manage.DbCommands, '_validate_engine')
  252. @mock.patch.object(manage.DbCommands, '_sync')
  253. def test_expand(self, mock_sync, mock_validate_engine,
  254. mock_get_alembic_branch_head,
  255. mock_get_current_alembic_heads):
  256. engine = mock_validate_engine.return_value
  257. engine.engine.name = 'mysql'
  258. mock_get_current_alembic_heads.side_effect = ['ocata_contract01',
  259. 'pike_expand01']
  260. mock_get_alembic_branch_head.side_effect = ['pike_expand01',
  261. 'pike_contract01']
  262. self.db.expand()
  263. mock_sync.assert_called_once_with(version='pike_expand01')
  264. @mock.patch(
  265. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  266. @mock.patch(
  267. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  268. @mock.patch.object(manage.DbCommands, '_validate_engine')
  269. def test_expand_if_not_expand_head(self, mock_validate_engine,
  270. mock_get_alembic_branch_head,
  271. mock_get_current_alembic_heads):
  272. engine = mock_validate_engine.return_value
  273. engine.engine.name = 'mysql'
  274. mock_get_current_alembic_heads.return_value = ['ocata_contract01']
  275. mock_get_alembic_branch_head.return_value = []
  276. exit = self.assertRaises(SystemExit, self.db.expand)
  277. self.assertIn('Database expansion failed. Couldn\'t find head '
  278. 'revision of expand branch.', exit.code)
  279. @mock.patch(
  280. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  281. @mock.patch(
  282. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  283. @mock.patch.object(manage.DbCommands, '_validate_engine')
  284. def test_expand_db_is_already_sync(self, mock_validate_engine,
  285. mock_get_alembic_branch_head,
  286. mock_get_current_alembic_heads):
  287. engine = mock_validate_engine.return_value
  288. engine.engine.name = 'mysql'
  289. mock_get_current_alembic_heads.return_value = ['pike_contract01']
  290. mock_get_alembic_branch_head.side_effect = ['pike_expand01',
  291. 'pike_contract01']
  292. self.assertRaises(SystemExit, self.db.expand)
  293. self.assertIn('Database is up to date. No migrations needed.',
  294. self.output.getvalue())
  295. @mock.patch(
  296. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  297. @mock.patch(
  298. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  299. @mock.patch.object(manage.DbCommands, '_validate_engine')
  300. def test_expand_already_sync(self, mock_validate_engine,
  301. mock_get_alembic_branch_head,
  302. mock_get_current_alembic_heads):
  303. engine = mock_validate_engine.return_value
  304. engine.engine.name = 'mysql'
  305. mock_get_current_alembic_heads.return_value = ['pike_expand01']
  306. mock_get_alembic_branch_head.side_effect = ['pike_expand01',
  307. 'pike_contract01']
  308. self.db.expand()
  309. self.assertIn('Database expansion is up to date. '
  310. 'No expansion needed.', self.output.getvalue())
  311. @mock.patch(
  312. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  313. @mock.patch(
  314. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  315. @mock.patch.object(manage.DbCommands, '_validate_engine')
  316. @mock.patch.object(manage.DbCommands, '_sync')
  317. def test_expand_failed(self, mock_sync, mock_validate_engine,
  318. mock_get_alembic_branch_head,
  319. mock_get_current_alembic_heads):
  320. engine = mock_validate_engine.return_value
  321. engine.engine.name = 'mysql'
  322. mock_get_current_alembic_heads.side_effect = ['ocata_contract01',
  323. 'test']
  324. mock_get_alembic_branch_head.side_effect = ['pike_expand01',
  325. 'pike_contract01']
  326. exit = self.assertRaises(SystemExit, self.db.expand)
  327. mock_sync.assert_called_once_with(version='pike_expand01')
  328. self.assertIn('Database expansion failed. Database expansion should '
  329. 'have brought the database version up to "pike_expand01"'
  330. ' revision. But, current revisions are: test ',
  331. exit.code)
  332. @mock.patch(
  333. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  334. @mock.patch(
  335. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  336. @mock.patch.object(manage.DbCommands, '_validate_engine')
  337. @mock.patch.object(manage.DbCommands, '_sync')
  338. def test_contract(self, mock_sync, mock_validate_engine,
  339. mock_get_alembic_branch_head,
  340. mock_get_current_alembic_heads):
  341. engine = mock_validate_engine.return_value
  342. engine.engine.name = 'mysql'
  343. mock_get_current_alembic_heads.side_effect = ['pike_expand01',
  344. 'pike_contract01']
  345. mock_get_alembic_branch_head.side_effect = ['pike_contract01',
  346. 'pike_expand01']
  347. self.db.contract()
  348. mock_sync.assert_called_once_with(version='pike_contract01')
  349. @mock.patch(
  350. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  351. @mock.patch(
  352. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  353. @mock.patch.object(manage.DbCommands, '_validate_engine')
  354. def test_contract_if_not_contract_head(self, mock_validate_engine,
  355. mock_get_alembic_branch_head,
  356. mock_get_current_alembic_heads):
  357. engine = mock_validate_engine.return_value
  358. engine.engine.name = 'mysql'
  359. mock_get_current_alembic_heads.return_value = ['ocata_contract01']
  360. mock_get_alembic_branch_head.return_value = []
  361. exit = self.assertRaises(SystemExit, self.db.contract)
  362. self.assertIn('Database contraction failed. Couldn\'t find head '
  363. 'revision of contract branch.', exit.code)
  364. @mock.patch(
  365. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  366. @mock.patch(
  367. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  368. @mock.patch.object(manage.DbCommands, '_validate_engine')
  369. def test_contract_db_is_already_sync(self, mock_validate_engine,
  370. mock_get_alembic_branch_head,
  371. mock_get_current_alembic_heads):
  372. engine = mock_validate_engine.return_value
  373. engine.engine.name = 'mysql'
  374. mock_get_current_alembic_heads.return_value = ['pike_contract01']
  375. mock_get_alembic_branch_head.side_effect = ['pike_contract01',
  376. 'pike_expand01']
  377. self.assertRaises(SystemExit, self.db.contract)
  378. self.assertIn('Database is up to date. No migrations needed.',
  379. self.output.getvalue())
  380. @mock.patch(
  381. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  382. @mock.patch(
  383. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  384. @mock.patch.object(manage.DbCommands, '_validate_engine')
  385. def test_contract_before_expand(self, mock_validate_engine,
  386. mock_get_alembic_branch_head,
  387. mock_get_current_alembic_heads):
  388. engine = mock_validate_engine.return_value
  389. engine.engine.name = 'mysql'
  390. mock_get_current_alembic_heads.return_value = ['ocata_contract01']
  391. mock_get_alembic_branch_head.side_effect = ['pike_expand01',
  392. 'pike_contract01']
  393. exit = self.assertRaises(SystemExit, self.db.contract)
  394. self.assertIn('Database contraction did not run. Database '
  395. 'contraction cannot be run before database expansion. '
  396. 'Run database expansion first using "glance-manage db '
  397. 'expand"', exit.code)
  398. @mock.patch(
  399. 'glance.db.sqlalchemy.alembic_migrations.data_migrations.'
  400. 'has_pending_migrations')
  401. @mock.patch(
  402. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  403. @mock.patch(
  404. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  405. @mock.patch.object(manage.DbCommands, '_validate_engine')
  406. def test_contract_before_migrate(self, mock_validate_engine,
  407. mock_get_alembic_branch_head,
  408. mock_get_curr_alembic_heads,
  409. mock_has_pending_migrations):
  410. engine = mock_validate_engine.return_value
  411. engine.engine.name = 'mysql'
  412. mock_get_curr_alembic_heads.side_effect = ['pike_expand01']
  413. mock_get_alembic_branch_head.side_effect = ['pike_contract01',
  414. 'pike_expand01']
  415. mock_has_pending_migrations.return_value = [mock.Mock()]
  416. exit = self.assertRaises(SystemExit, self.db.contract)
  417. self.assertIn('Database contraction did not run. Database '
  418. 'contraction cannot be run before data migration is '
  419. 'complete. Run data migration using "glance-manage db '
  420. 'migrate".', exit.code)
  421. @mock.patch(
  422. 'glance.db.sqlalchemy.alembic_migrations.data_migrations.'
  423. 'has_pending_migrations')
  424. @mock.patch(
  425. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  426. @mock.patch(
  427. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  428. @mock.patch.object(manage.DbCommands, '_validate_engine')
  429. def test_migrate(self, mock_validate_engine, mock_get_alembic_branch_head,
  430. mock_get_current_alembic_heads,
  431. mock_has_pending_migrations):
  432. engine = mock_validate_engine.return_value
  433. engine.engine.name = 'mysql'
  434. mock_get_current_alembic_heads.side_effect = ['pike_expand01',
  435. 'pike_contract01']
  436. mock_get_alembic_branch_head.side_effect = ['pike_contract01',
  437. 'pike_expand01']
  438. mock_has_pending_migrations.return_value = None
  439. self.db.migrate()
  440. self.assertIn('Database migration is up to date. '
  441. 'No migration needed.', self.output.getvalue())
  442. @mock.patch(
  443. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  444. @mock.patch(
  445. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  446. @mock.patch.object(manage.DbCommands, '_validate_engine')
  447. def test_migrate_db_is_already_sync(self, mock_validate_engine,
  448. mock_get_alembic_branch_head,
  449. mock_get_current_alembic_heads):
  450. engine = mock_validate_engine.return_value
  451. engine.engine.name = 'mysql'
  452. mock_get_current_alembic_heads.return_value = ['pike_contract01']
  453. mock_get_alembic_branch_head.side_effect = ['pike_contract01',
  454. 'pike_expand01']
  455. self.assertRaises(SystemExit, self.db.migrate)
  456. self.assertIn('Database is up to date. No migrations needed.',
  457. self.output.getvalue())
  458. @mock.patch(
  459. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  460. @mock.patch(
  461. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  462. @mock.patch.object(manage.DbCommands, '_validate_engine')
  463. def test_migrate_already_sync(self, mock_validate_engine,
  464. mock_get_alembic_branch_head,
  465. mock_get_current_alembic_heads):
  466. engine = mock_validate_engine.return_value
  467. engine.engine.name = 'mysql'
  468. mock_get_current_alembic_heads.return_value = ['ocata_contract01']
  469. mock_get_alembic_branch_head.side_effect = ['pike_contract01',
  470. 'pike_expand01']
  471. exit = self.assertRaises(SystemExit, self.db.migrate)
  472. self.assertIn('Data migration did not run. Data migration cannot be '
  473. 'run before database expansion. Run database expansion '
  474. 'first using "glance-manage db expand"', exit.code)
  475. @mock.patch(
  476. 'glance.db.sqlalchemy.alembic_migrations.data_migrations.'
  477. 'has_pending_migrations')
  478. @mock.patch(
  479. 'glance.db.sqlalchemy.alembic_migrations.get_current_alembic_heads')
  480. @mock.patch(
  481. 'glance.db.sqlalchemy.alembic_migrations.get_alembic_branch_head')
  482. @mock.patch.object(manage.DbCommands, '_validate_engine')
  483. def test_migrate_before_expand(self, mock_validate_engine,
  484. mock_get_alembic_branch_head,
  485. mock_get_current_alembic_heads,
  486. mock_has_pending_migrations):
  487. engine = mock_validate_engine.return_value
  488. engine.engine.name = 'mysql'
  489. mock_get_current_alembic_heads.return_value = ['pike_expand01']
  490. mock_get_alembic_branch_head.side_effect = ['pike_contract01',
  491. 'pike_expand01']
  492. mock_has_pending_migrations.return_value = None
  493. self.db.migrate()
  494. self.assertIn('Database migration is up to date. '
  495. 'No migration needed.', self.output.getvalue())
  496. @mock.patch.object(manage.DbCommands, 'version')
  497. def test_db_version(self, version):
  498. self._main_test_helper(['glance.cmd.manage', 'db', 'version'],
  499. manage.DbCommands.version)
  500. @mock.patch.object(manage.DbCommands, 'check')
  501. def test_db_check(self, check):
  502. self._main_test_helper(['glance.cmd.manage', 'db', 'check'],
  503. manage.DbCommands.check)
  504. @mock.patch.object(manage.DbCommands, 'sync')
  505. def test_db_sync(self, sync):
  506. self._main_test_helper(['glance.cmd.manage', 'db', 'sync'],
  507. manage.DbCommands.sync)
  508. @mock.patch.object(manage.DbCommands, 'upgrade')
  509. def test_db_upgrade(self, upgrade):
  510. self._main_test_helper(['glance.cmd.manage', 'db', 'upgrade'],
  511. manage.DbCommands.upgrade)
  512. @mock.patch.object(manage.DbCommands, 'version_control')
  513. def test_db_version_control(self, version_control):
  514. self._main_test_helper(['glance.cmd.manage', 'db', 'version_control'],
  515. manage.DbCommands.version_control)
  516. @mock.patch.object(manage.DbCommands, 'sync')
  517. def test_db_sync_version(self, sync):
  518. self._main_test_helper(['glance.cmd.manage', 'db', 'sync', 'liberty'],
  519. manage.DbCommands.sync, 'liberty')
  520. @mock.patch.object(manage.DbCommands, 'upgrade')
  521. def test_db_upgrade_version(self, upgrade):
  522. self._main_test_helper(['glance.cmd.manage', 'db',
  523. 'upgrade', 'liberty'],
  524. manage.DbCommands.upgrade, 'liberty')
  525. @mock.patch.object(manage.DbCommands, 'expand')
  526. def test_db_expand(self, expand):
  527. self._main_test_helper(['glance.cmd.manage', 'db', 'expand'],
  528. manage.DbCommands.expand)
  529. @mock.patch.object(manage.DbCommands, 'migrate')
  530. def test_db_migrate(self, migrate):
  531. self._main_test_helper(['glance.cmd.manage', 'db', 'migrate'],
  532. manage.DbCommands.migrate)
  533. @mock.patch.object(manage.DbCommands, 'contract')
  534. def test_db_contract(self, contract):
  535. self._main_test_helper(['glance.cmd.manage', 'db', 'contract'],
  536. manage.DbCommands.contract)
  537. def test_db_metadefs_unload(self):
  538. db_metadata.db_unload_metadefs = mock.Mock()
  539. self._main_test_helper(['glance.cmd.manage', 'db', 'unload_metadefs'],
  540. db_metadata.db_unload_metadefs,
  541. db_api.get_engine())
  542. def test_db_metadefs_load(self):
  543. db_metadata.db_load_metadefs = mock.Mock()
  544. self._main_test_helper(['glance.cmd.manage', 'db', 'load_metadefs'],
  545. db_metadata.db_load_metadefs,
  546. db_api.get_engine(),
  547. None, False, False, False)
  548. def test_db_metadefs_load_with_specified_path(self):
  549. db_metadata.db_load_metadefs = mock.Mock()
  550. self._main_test_helper(['glance.cmd.manage', 'db', 'load_metadefs',
  551. '--path', '/mock/'],
  552. db_metadata.db_load_metadefs,
  553. db_api.get_engine(),
  554. '/mock/', False, False, False)
  555. def test_db_metadefs_load_prefer_new_with_path(self):
  556. db_metadata.db_load_metadefs = mock.Mock()
  557. self._main_test_helper(['glance.cmd.manage', 'db', 'load_metadefs',
  558. '--path', '/mock/', '--merge', '--prefer_new'],
  559. db_metadata.db_load_metadefs,
  560. db_api.get_engine(),
  561. '/mock/', True, True, False)
  562. def test_db_metadefs_load_prefer_new(self):
  563. db_metadata.db_load_metadefs = mock.Mock()
  564. self._main_test_helper(['glance.cmd.manage', 'db', 'load_metadefs',
  565. '--merge', '--prefer_new'],
  566. db_metadata.db_load_metadefs,
  567. db_api.get_engine(),
  568. None, True, True, False)
  569. def test_db_metadefs_load_overwrite_existing(self):
  570. db_metadata.db_load_metadefs = mock.Mock()
  571. self._main_test_helper(['glance.cmd.manage', 'db', 'load_metadefs',
  572. '--merge', '--overwrite'],
  573. db_metadata.db_load_metadefs,
  574. db_api.get_engine(),
  575. None, True, False, True)
  576. def test_db_metadefs_load_prefer_new_and_overwrite_existing(self):
  577. db_metadata.db_load_metadefs = mock.Mock()
  578. self._main_test_helper(['glance.cmd.manage', 'db', 'load_metadefs',
  579. '--merge', '--prefer_new', '--overwrite'],
  580. db_metadata.db_load_metadefs,
  581. db_api.get_engine(),
  582. None, True, True, True)
  583. def test_db_metadefs_load_from_path_overwrite_existing(self):
  584. db_metadata.db_load_metadefs = mock.Mock()
  585. self._main_test_helper(['glance.cmd.manage', 'db', 'load_metadefs',
  586. '--path', '/mock/', '--merge', '--overwrite'],
  587. db_metadata.db_load_metadefs,
  588. db_api.get_engine(),
  589. '/mock/', True, False, True)
  590. def test_db_metadefs_export(self):
  591. db_metadata.db_export_metadefs = mock.Mock()
  592. self._main_test_helper(['glance.cmd.manage', 'db', 'export_metadefs'],
  593. db_metadata.db_export_metadefs,
  594. db_api.get_engine(),
  595. None)
  596. def test_db_metadefs_export_with_specified_path(self):
  597. db_metadata.db_export_metadefs = mock.Mock()
  598. self._main_test_helper(['glance.cmd.manage', 'db', 'export_metadefs',
  599. '--path', '/mock/'],
  600. db_metadata.db_export_metadefs,
  601. db_api.get_engine(),
  602. '/mock/')