No Description
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_datasource.py 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #
  2. # This file is part of Lodel 2 (https://github.com/OpenEdition)
  3. #
  4. # Copyright (C) 2015-2017 Cléo UMS-3287
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU Affero General Public License as published
  8. # by the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU Affero General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU Affero General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. import copy
  20. import datetime
  21. import unittest
  22. from unittest import mock
  23. from unittest.mock import patch
  24. import tests.loader_utils
  25. from tests.leapi.query.utils import dyncode_module as dyncode
  26. from lodel.leapi.query import LeDeleteQuery, LeUpdateQuery, LeGetQuery, \
  27. LeInsertQuery
  28. from lodel.leapi.exceptions import *
  29. class LeQueryDatasourceTestCase(unittest.TestCase):
  30. """ Testing LeQuery objects connection with datasource """
  31. mockread = mock.MagicMock()
  32. mockwrite = mock.MagicMock()
  33. dyncode = None
  34. @classmethod
  35. def setUpClass(cls):
  36. """ Mocking read & write datasource of dyncode """
  37. cls.dyncode = dict()
  38. for dyncls in dyncode.dynclasses:
  39. dyncls._ro_datasource = cls.mockread
  40. dyncls._rw_datasource = cls.mockwrite
  41. cls.dyncode[dyncls.__name__] = dyncls
  42. def setUp(self):
  43. """ Reseting all mock calls before test """
  44. self.mockread.reset_mock()
  45. self.mockwrite.reset_mock()
  46. def check_nocall(self, read = True, exclude = None):
  47. """ Utility function to check if a datasource mock method has been
  48. called during test """
  49. exclude = [] if exclude is None else exclude
  50. if read:
  51. mockds = self.mockread
  52. else:
  53. mockds = self.mockwrite
  54. if 'select' not in exclude:
  55. self.assertFalse(
  56. mockds.select.called,
  57. "select method was not expected to be called")
  58. if 'delete' not in exclude:
  59. self.assertFalse(
  60. mockds.delete.called,
  61. "delete method was not expected to be called")
  62. if 'update' not in exclude:
  63. self.assertFalse(
  64. mockds.update.called,
  65. "update method was not expected to be called")
  66. if 'insert' not in exclude:
  67. self.assertFalse(
  68. mockds.insert.called,
  69. "insert method was not expected to be called")
  70. def test_delete_simple_filter(self):
  71. """ Testing delete query mocking datasource using simple query
  72. filters """
  73. cls = self.dyncode['Person']
  74. query = LeDeleteQuery(
  75. target_class = cls,
  76. query_filter = ['lodel_id = 1', 'alias.lodel_id = 2'])
  77. query.execute()
  78. # Cannot check with assert_called_once_with because of the array
  79. # that is not in a deterministic order
  80. call_args = self.mockwrite.delete.call_args[0]
  81. self.assertEqual(call_args[0], cls)
  82. self.assertEqual(
  83. sorted(call_args[1]),
  84. sorted([('lodel_id', '=', 1), ('alias', '=', '2')]))
  85. self.assertEqual(call_args[2], [])
  86. self.check_nocall(read = False, exclude = ['delete'])
  87. self.check_nocall(read = True)
  88. def test_delete_simple_rel_filters(self):
  89. """ Testing delete query mocking datasource using simple filters
  90. and relationnal filters"""
  91. cls = self.dyncode['Person']
  92. query = LeDeleteQuery(
  93. target_class = cls,
  94. query_filter = ['lodel_id = 1', 'alias.firstname = foo'])
  95. query.execute()
  96. self.mockwrite.delete.assert_called_once_with(
  97. cls,
  98. [('lodel_id', '=', 1)],
  99. [(('alias', {cls: 'firstname'}), '=', 'foo')])
  100. self.check_nocall(read = False, exclude = ['delete'])
  101. self.check_nocall(read = True)
  102. def test_delete_rel_filters(self):
  103. """ Testing delete query mocking datasource """
  104. cls = self.dyncode['Person']
  105. query = LeDeleteQuery(
  106. target_class = cls,
  107. query_filter = ['alias.firstname = foo'])
  108. query.execute()
  109. self.mockwrite.delete.assert_called_once_with(
  110. cls,
  111. [],
  112. [(('alias', {cls: 'firstname'}), '=', 'foo')])
  113. self.check_nocall(read = False, exclude = ['delete'])
  114. self.check_nocall(read = True)
  115. @unittest.skip("Waiting references checks stack implementation")
  116. def test_insert(self):
  117. """ Testing LeInsertQuery mocking datasource """
  118. cls = self.dyncode['Person']
  119. query = LeInsertQuery(
  120. target_class = cls)
  121. self.mockwrite.insert.return_value = 1
  122. datas = {
  123. 'firstname': 'foo',
  124. 'lastname': 'bar',
  125. 'alias': None}
  126. query.execute(datas)
  127. self.assertEqual(self.mockwrite.insert.call_count, 1)
  128. cargs , _ = self.mockwrite.insert.call_args
  129. pdatas = cls.prepare_datas(datas, True, False)
  130. self.assertEqual(cargs[0], cls)
  131. cargs = cargs[1]
  132. self.assertEqual(set(pdatas.keys()), set(cargs.keys()))
  133. for dname in pdatas:
  134. if isinstance(pdatas[dname], datetime.datetime):
  135. d1 = pdatas[dname]
  136. d2 = cargs[dname]
  137. for vname in ('year', 'month', 'day', 'hour', 'minute'):
  138. self.assertEqual(
  139. getattr(d1, vname), getattr(d2, vname))
  140. pass
  141. else:
  142. self.assertEqual(pdatas[dname], cargs[dname])
  143. self.check_nocall(read = False, exclude = ['insert'])
  144. self.check_nocall(read = True)
  145. def test_update_instance(self):
  146. """ Testing LeUpdateQuery with an instance mocking datasource """
  147. cls = self.dyncode['Person']
  148. inst = cls(lodel_id = 1, firstname = 'foo', lastname = 'bar',
  149. alias = None, linked_texts = None)
  150. query = LeUpdateQuery(inst)
  151. with self.assertRaises(LeApiQueryError):
  152. # Bad call, giving data while an instance was given to __init__
  153. query.execute(data = {'firstname': 'ooba'})
  154. query.execute()
  155. self.mockwrite.update.assert_called_once_with(
  156. cls,
  157. [('lodel_id', '=', '1')],
  158. [],
  159. inst.datas(True))
  160. self.check_nocall(read=False, exclude = ['update'])
  161. self.check_nocall(read=True)
  162. def test_update_filter(self):
  163. """ Testing LeUpdateQuery with filter mocking datasource """
  164. cls = self.dyncode['Person']
  165. fake_db_datas = [{
  166. 'lodel_id': 1,
  167. 'firstname': 'barfoo',
  168. 'lastname': 'foobar',
  169. 'fullname': 'barfoo foobar',
  170. 'alias': None,
  171. 'linked_texts': None,
  172. 'help_text': None,
  173. 'classname': 'Person',
  174. 'date_create': None,
  175. 'date_update': None}]
  176. q_datas = {'firstname': 'foobar', 'lastname': 'barfoo'}
  177. expt_datas = copy.copy(fake_db_datas[0])
  178. expt_datas.update(q_datas)
  179. expt_datas = cls.prepare_datas(expt_datas, True, True)
  180. query = LeUpdateQuery(cls, [('lodel_id', '=', 1)])
  181. with self.assertRaises(LeApiQueryError):
  182. # Bad call, no datas given while a class and a filters were given
  183. # to __init__
  184. query.execute()
  185. self.mockread.select.return_value = fake_db_datas
  186. query.execute(q_datas)
  187. self.mockwrite.update.asser_called_once_with(
  188. cls,
  189. [('lodel_id', '=', '1')],
  190. [],
  191. expt_datas)