|
@@ -0,0 +1,125 @@
|
|
1
|
+"""
|
|
2
|
+ Tests for MySQL Datasource
|
|
3
|
+"""
|
|
4
|
+
|
|
5
|
+import random
|
|
6
|
+import copy
|
|
7
|
+
|
|
8
|
+import unittest
|
|
9
|
+import unittest.mock as mock
|
|
10
|
+from unittest import TestCase
|
|
11
|
+from unittest.mock import patch, Mock, call
|
|
12
|
+
|
|
13
|
+import mosql
|
|
14
|
+import mosql.db
|
|
15
|
+from mosql.util import Query as mosql_Query
|
|
16
|
+import pymysql
|
|
17
|
+
|
|
18
|
+import leapi.test.utils #Code generation functions
|
|
19
|
+
|
|
20
|
+import Lodel.settings
|
|
21
|
+import DataSource.MySQL
|
|
22
|
+from DataSource.MySQL.leapidatasource import LeDataSourceSQL as DataSource
|
|
23
|
+from DataSource.MySQL.common_utils import MySQL as db_utils
|
|
24
|
+from EditorialModel.classtypes import common_fields, relations_common_fields
|
|
25
|
+
|
|
26
|
+class DataSourceTestCase(TestCase):
|
|
27
|
+ #Dynamic code generation & import
|
|
28
|
+ @classmethod
|
|
29
|
+ def setUpClass(cls):
|
|
30
|
+ """ Write the generated code in a temporary directory and import it """
|
|
31
|
+ cls.tmpdir = leapi.test.utils.tmp_load_factory_code()
|
|
32
|
+ @classmethod
|
|
33
|
+ def tearDownClass(cls):
|
|
34
|
+ """ Remove the temporary directory created at class setup """
|
|
35
|
+ leapi.test.utils.cleanup(cls.tmpdir)
|
|
36
|
+
|
|
37
|
+ def test_init(self):
|
|
38
|
+ """ Test __init__ for datasource """
|
|
39
|
+ with patch.object(mosql.db.Database, '__init__', return_value=None) as mock_db:
|
|
40
|
+ #Test __init__ without arguments
|
|
41
|
+ DataSource()
|
|
42
|
+ conn_args = db_utils.connections['default']
|
|
43
|
+ db_module = conn_args['module']
|
|
44
|
+ del(conn_args['module'])
|
|
45
|
+ mock_db.assert_called_once_with(db_module, **conn_args)
|
|
46
|
+
|
|
47
|
+ mock_db.reset_mock()
|
|
48
|
+ #test with arguments
|
|
49
|
+ conn_args = { 'hello': 'world', 'answer': 42 }
|
|
50
|
+ DataSource(mosql, conn_args)
|
|
51
|
+ mock_db.assert_called_once_with(mosql, **conn_args)
|
|
52
|
+
|
|
53
|
+ mock_db.reset_mock()
|
|
54
|
+
|
|
55
|
+ DataSource(conn_args = conn_args)
|
|
56
|
+ mock_db.assert_called_once_with(pymysql, **conn_args)
|
|
57
|
+
|
|
58
|
+ def test_insert_leobject(self):
|
|
59
|
+ """ Test the insert method on LeObjects """
|
|
60
|
+ from dyncode import Article, Personne, Rubrique
|
|
61
|
+
|
|
62
|
+ for letype in [Article, Personne, Rubrique]:
|
|
63
|
+ lodel_id = random.randint(0,4096) # Choose a random lodel_id
|
|
64
|
+
|
|
65
|
+ # Mock the cursor to superseed the lastrowid property
|
|
66
|
+ cursor_mock = Mock()
|
|
67
|
+ cursor_mock.lastrowid = lodel_id
|
|
68
|
+ # Mock the cursor() call on connection
|
|
69
|
+ cursor_call_mock = Mock(return_value=cursor_mock)
|
|
70
|
+ # Mock the connection to set the cursor() call mock
|
|
71
|
+ connection_mock = Mock()
|
|
72
|
+ connection_mock.cursor = cursor_call_mock
|
|
73
|
+ # Mock the connect() call on dbmodule to bla bla
|
|
74
|
+ connect_call_mock = Mock(return_value=connection_mock)
|
|
75
|
+ # Mock the db module to set the connection mock (on connect() call)
|
|
76
|
+ dbmodule_mock = Mock()
|
|
77
|
+ dbmodule_mock.connect = connect_call_mock
|
|
78
|
+
|
|
79
|
+ datasource = DataSource(module=dbmodule_mock, conn_args = {})
|
|
80
|
+
|
|
81
|
+ sql_query = 'SELECT wow FROM splendid_table'
|
|
82
|
+
|
|
83
|
+ class_table_datas = { 'title': 'foo', 'number': 42 }
|
|
84
|
+ object_table_datas = { 'string': random.randint(-42,42) }
|
|
85
|
+
|
|
86
|
+ # build the insert datas argument
|
|
87
|
+ insert_datas = copy.copy(object_table_datas)
|
|
88
|
+ insert_datas.update(class_table_datas)
|
|
89
|
+
|
|
90
|
+ with patch.object(mosql_Query, '__call__', return_value=sql_query) as mock_insert:
|
|
91
|
+ with patch.object(db_utils, 'query', return_value=cursor_mock) as mock_utils_query:
|
|
92
|
+ #mock_utils_query = Mock()
|
|
93
|
+ #db_utils.query = mock_utils_query
|
|
94
|
+
|
|
95
|
+ # call the insert() method
|
|
96
|
+ datasource.insert(letype, **insert_datas)
|
|
97
|
+
|
|
98
|
+ # construct expected datas for object table insert
|
|
99
|
+ object_table_datas['class_id'] = letype._class_id
|
|
100
|
+ object_table_datas['type_id'] = letype._type_id
|
|
101
|
+ # construct expected datas used in class table insert
|
|
102
|
+ class_table_datas['lodel_id'] = lodel_id
|
|
103
|
+
|
|
104
|
+ expected_calls = [
|
|
105
|
+ # insert in object table call
|
|
106
|
+ call(
|
|
107
|
+ db_utils.objects_table_name,
|
|
108
|
+ object_table_datas
|
|
109
|
+ ),
|
|
110
|
+ # insert in class specific table call
|
|
111
|
+ call(
|
|
112
|
+ db_utils.get_table_name_from_class(letype._leclass.__name__),
|
|
113
|
+ class_table_datas
|
|
114
|
+ ),
|
|
115
|
+ ]
|
|
116
|
+
|
|
117
|
+ expected_utils_query_calls = [
|
|
118
|
+ call(datasource.connection, sql_query),
|
|
119
|
+ call(datasource.connection, sql_query),
|
|
120
|
+ ]
|
|
121
|
+
|
|
122
|
+ mock_insert.assert_has_calls(expected_calls, any_order = False)
|
|
123
|
+ mock_utils_query.assert_has_calls(expected_utils_query_calls)
|
|
124
|
+
|
|
125
|
+
|