User | Revision | Line number | New contents of line |
switches |
0:0e018d759a2a
|
1
|
"""
|
switches |
0:0e018d759a2a
|
2
|
mbed SDK
|
switches |
0:0e018d759a2a
|
3
|
Copyright (c) 2011-2014 ARM Limited
|
switches |
0:0e018d759a2a
|
4
|
|
switches |
0:0e018d759a2a
|
5
|
Licensed under the Apache License, Version 2.0 (the "License");
|
switches |
0:0e018d759a2a
|
6
|
you may not use this file except in compliance with the License.
|
switches |
0:0e018d759a2a
|
7
|
You may obtain a copy of the License at
|
switches |
0:0e018d759a2a
|
8
|
|
switches |
0:0e018d759a2a
|
9
|
http://www.apache.org/licenses/LICENSE-2.0
|
switches |
0:0e018d759a2a
|
10
|
|
switches |
0:0e018d759a2a
|
11
|
Unless required by applicable law or agreed to in writing, software
|
switches |
0:0e018d759a2a
|
12
|
distributed under the License is distributed on an "AS IS" BASIS,
|
switches |
0:0e018d759a2a
|
13
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
switches |
0:0e018d759a2a
|
14
|
See the License for the specific language governing permissions and
|
switches |
0:0e018d759a2a
|
15
|
limitations under the License.
|
switches |
0:0e018d759a2a
|
16
|
|
switches |
0:0e018d759a2a
|
17
|
Author: Przemyslaw Wirkus <Przemyslaw.Wirkus@arm.com>
|
switches |
0:0e018d759a2a
|
18
|
"""
|
switches |
0:0e018d759a2a
|
19
|
|
switches |
0:0e018d759a2a
|
20
|
import re
|
switches |
0:0e018d759a2a
|
21
|
import MySQLdb as mdb
|
switches |
0:0e018d759a2a
|
22
|
|
switches |
0:0e018d759a2a
|
23
|
# Imports from TEST API
|
switches |
0:0e018d759a2a
|
24
|
from tools.test_db import BaseDBAccess
|
switches |
0:0e018d759a2a
|
25
|
|
switches |
0:0e018d759a2a
|
26
|
|
switches |
0:0e018d759a2a
|
27
|
class MySQLDBAccess(BaseDBAccess):
|
switches |
0:0e018d759a2a
|
28
|
""" Wrapper for MySQL DB access for common test suite interface
|
switches |
0:0e018d759a2a
|
29
|
"""
|
switches |
0:0e018d759a2a
|
30
|
def __init__(self):
|
switches |
0:0e018d759a2a
|
31
|
BaseDBAccess.__init__(self)
|
switches |
0:0e018d759a2a
|
32
|
self.DB_TYPE = 'mysql'
|
switches |
0:0e018d759a2a
|
33
|
|
switches |
0:0e018d759a2a
|
34
|
def detect_database(self, verbose=False):
|
switches |
0:0e018d759a2a
|
35
|
""" detect database and return VERION data structure or string (verbose=True)
|
switches |
0:0e018d759a2a
|
36
|
"""
|
switches |
0:0e018d759a2a
|
37
|
query = 'SHOW VARIABLES LIKE "%version%"'
|
switches |
0:0e018d759a2a
|
38
|
rows = self.select_all(query)
|
switches |
0:0e018d759a2a
|
39
|
if verbose:
|
switches |
0:0e018d759a2a
|
40
|
result = []
|
switches |
0:0e018d759a2a
|
41
|
for row in rows:
|
switches |
0:0e018d759a2a
|
42
|
result.append("\t%s: %s"% (row['Variable_name'], row['Value']))
|
switches |
0:0e018d759a2a
|
43
|
result = "\n".join(result)
|
switches |
0:0e018d759a2a
|
44
|
else:
|
switches |
0:0e018d759a2a
|
45
|
result = rows
|
switches |
0:0e018d759a2a
|
46
|
return result
|
switches |
0:0e018d759a2a
|
47
|
|
switches |
0:0e018d759a2a
|
48
|
def parse_db_connection_string(self, str):
|
switches |
0:0e018d759a2a
|
49
|
""" Parsing SQL DB connection string. String should contain:
|
switches |
0:0e018d759a2a
|
50
|
- DB Name, user name, password, URL (DB host), name
|
switches |
0:0e018d759a2a
|
51
|
Function should return tuple with parsed (host, user, passwd, db) or None if error
|
switches |
0:0e018d759a2a
|
52
|
E.g. connection string: 'mysql://username:password@127.0.0.1/db_name'
|
switches |
0:0e018d759a2a
|
53
|
"""
|
switches |
0:0e018d759a2a
|
54
|
result = BaseDBAccess().parse_db_connection_string(str)
|
switches |
0:0e018d759a2a
|
55
|
if result is not None:
|
switches |
0:0e018d759a2a
|
56
|
(db_type, username, password, host, db_name) = result
|
switches |
0:0e018d759a2a
|
57
|
if db_type != 'mysql':
|
switches |
0:0e018d759a2a
|
58
|
result = None
|
switches |
0:0e018d759a2a
|
59
|
return result
|
switches |
0:0e018d759a2a
|
60
|
|
switches |
0:0e018d759a2a
|
61
|
def is_connected(self):
|
switches |
0:0e018d759a2a
|
62
|
""" Returns True if we are connected to database
|
switches |
0:0e018d759a2a
|
63
|
"""
|
switches |
0:0e018d759a2a
|
64
|
return self.db_object is not None
|
switches |
0:0e018d759a2a
|
65
|
|
switches |
0:0e018d759a2a
|
66
|
def connect(self, host, user, passwd, db):
|
switches |
0:0e018d759a2a
|
67
|
""" Connects to DB and returns DB object
|
switches |
0:0e018d759a2a
|
68
|
"""
|
switches |
0:0e018d759a2a
|
69
|
try:
|
switches |
0:0e018d759a2a
|
70
|
self.db_object = mdb.connect(host=host, user=user, passwd=passwd, db=db)
|
switches |
0:0e018d759a2a
|
71
|
# Let's remember connection credentials
|
switches |
0:0e018d759a2a
|
72
|
self.db_type = self.DB_TYPE
|
switches |
0:0e018d759a2a
|
73
|
self.host = host
|
switches |
0:0e018d759a2a
|
74
|
self.user = user
|
switches |
0:0e018d759a2a
|
75
|
self.passwd = passwd
|
switches |
0:0e018d759a2a
|
76
|
self.db = db
|
switches |
0:0e018d759a2a
|
77
|
except mdb.Error, e:
|
switches |
0:0e018d759a2a
|
78
|
print "Error %d: %s"% (e.args[0], e.args[1])
|
switches |
0:0e018d759a2a
|
79
|
self.db_object = None
|
switches |
0:0e018d759a2a
|
80
|
self.db_type = None
|
switches |
0:0e018d759a2a
|
81
|
self.host = None
|
switches |
0:0e018d759a2a
|
82
|
self.user = None
|
switches |
0:0e018d759a2a
|
83
|
self.passwd = None
|
switches |
0:0e018d759a2a
|
84
|
self.db = None
|
switches |
0:0e018d759a2a
|
85
|
|
switches |
0:0e018d759a2a
|
86
|
def connect_url(self, db_url):
|
switches |
0:0e018d759a2a
|
87
|
""" Connects to database using db_url (database url parsing),
|
switches |
0:0e018d759a2a
|
88
|
store host, username, password, db_name
|
switches |
0:0e018d759a2a
|
89
|
"""
|
switches |
0:0e018d759a2a
|
90
|
result = self.parse_db_connection_string(db_url)
|
switches |
0:0e018d759a2a
|
91
|
if result is not None:
|
switches |
0:0e018d759a2a
|
92
|
(db_type, username, password, host, db_name) = result
|
switches |
0:0e018d759a2a
|
93
|
if db_type == self.DB_TYPE:
|
switches |
0:0e018d759a2a
|
94
|
self.connect(host, username, password, db_name)
|
switches |
0:0e018d759a2a
|
95
|
|
switches |
0:0e018d759a2a
|
96
|
def reconnect(self):
|
switches |
0:0e018d759a2a
|
97
|
""" Reconnects to DB and returns DB object using stored host name,
|
switches |
0:0e018d759a2a
|
98
|
database name and credentials (user name and password)
|
switches |
0:0e018d759a2a
|
99
|
"""
|
switches |
0:0e018d759a2a
|
100
|
self.connect(self.host, self.user, self.passwd, self.db)
|
switches |
0:0e018d759a2a
|
101
|
|
switches |
0:0e018d759a2a
|
102
|
def disconnect(self):
|
switches |
0:0e018d759a2a
|
103
|
""" Close DB connection
|
switches |
0:0e018d759a2a
|
104
|
"""
|
switches |
0:0e018d759a2a
|
105
|
if self.db_object:
|
switches |
0:0e018d759a2a
|
106
|
self.db_object.close()
|
switches |
0:0e018d759a2a
|
107
|
self.db_object = None
|
switches |
0:0e018d759a2a
|
108
|
self.db_type = None
|
switches |
0:0e018d759a2a
|
109
|
|
switches |
0:0e018d759a2a
|
110
|
def escape_string(self, str):
|
switches |
0:0e018d759a2a
|
111
|
""" Escapes string so it can be put in SQL query between quotes
|
switches |
0:0e018d759a2a
|
112
|
"""
|
switches |
0:0e018d759a2a
|
113
|
con = self.db_object
|
switches |
0:0e018d759a2a
|
114
|
result = con.escape_string(str)
|
switches |
0:0e018d759a2a
|
115
|
return result if result else ''
|
switches |
0:0e018d759a2a
|
116
|
|
switches |
0:0e018d759a2a
|
117
|
def select_all(self, query):
|
switches |
0:0e018d759a2a
|
118
|
""" Execute SELECT query and get all results
|
switches |
0:0e018d759a2a
|
119
|
"""
|
switches |
0:0e018d759a2a
|
120
|
con = self.db_object
|
switches |
0:0e018d759a2a
|
121
|
cur = con.cursor(mdb.cursors.DictCursor)
|
switches |
0:0e018d759a2a
|
122
|
cur.execute(query)
|
switches |
0:0e018d759a2a
|
123
|
rows = cur.fetchall()
|
switches |
0:0e018d759a2a
|
124
|
return rows
|
switches |
0:0e018d759a2a
|
125
|
|
switches |
0:0e018d759a2a
|
126
|
def insert(self, query, commit=True):
|
switches |
0:0e018d759a2a
|
127
|
""" Execute INSERT query, define if you want to commit
|
switches |
0:0e018d759a2a
|
128
|
"""
|
switches |
0:0e018d759a2a
|
129
|
con = self.db_object
|
switches |
0:0e018d759a2a
|
130
|
cur = con.cursor()
|
switches |
0:0e018d759a2a
|
131
|
cur.execute(query)
|
switches |
0:0e018d759a2a
|
132
|
if commit:
|
switches |
0:0e018d759a2a
|
133
|
con.commit()
|
switches |
0:0e018d759a2a
|
134
|
return cur.lastrowid
|
switches |
0:0e018d759a2a
|
135
|
|
switches |
0:0e018d759a2a
|
136
|
def get_next_build_id(self, name, desc='', location='', type=None, status=None):
|
switches |
0:0e018d759a2a
|
137
|
""" Insert new build_id (DB unique build like ID number to send all test results)
|
switches |
0:0e018d759a2a
|
138
|
"""
|
switches |
0:0e018d759a2a
|
139
|
if status is None:
|
switches |
0:0e018d759a2a
|
140
|
status = self.BUILD_ID_STATUS_STARTED
|
switches |
0:0e018d759a2a
|
141
|
|
switches |
0:0e018d759a2a
|
142
|
if type is None:
|
switches |
0:0e018d759a2a
|
143
|
type = self.BUILD_ID_TYPE_TEST
|
switches |
0:0e018d759a2a
|
144
|
|
switches |
0:0e018d759a2a
|
145
|
query = """INSERT INTO `%s` (%s_name, %s_desc, %s_location, %s_type_fk, %s_status_fk)
|
switches |
0:0e018d759a2a
|
146
|
VALUES ('%s', '%s', '%s', %d, %d)"""% (self.TABLE_BUILD_ID,
|
switches |
0:0e018d759a2a
|
147
|
self.TABLE_BUILD_ID,
|
switches |
0:0e018d759a2a
|
148
|
self.TABLE_BUILD_ID,
|
switches |
0:0e018d759a2a
|
149
|
self.TABLE_BUILD_ID,
|
switches |
0:0e018d759a2a
|
150
|
self.TABLE_BUILD_ID,
|
switches |
0:0e018d759a2a
|
151
|
self.TABLE_BUILD_ID,
|
switches |
0:0e018d759a2a
|
152
|
self.escape_string(name),
|
switches |
0:0e018d759a2a
|
153
|
self.escape_string(desc),
|
switches |
0:0e018d759a2a
|
154
|
self.escape_string(location),
|
switches |
0:0e018d759a2a
|
155
|
type,
|
switches |
0:0e018d759a2a
|
156
|
status)
|
switches |
0:0e018d759a2a
|
157
|
index = self.insert(query) # Provide inserted record PK
|
switches |
0:0e018d759a2a
|
158
|
return index
|
switches |
0:0e018d759a2a
|
159
|
|
switches |
0:0e018d759a2a
|
160
|
def get_table_entry_pk(self, table, column, value, update_db=True):
|
switches |
0:0e018d759a2a
|
161
|
""" Checks for entries in tables with two columns (<TABLE_NAME>_pk, <column>)
|
switches |
0:0e018d759a2a
|
162
|
If update_db is True updates table entry if value in specified column doesn't exist
|
switches |
0:0e018d759a2a
|
163
|
"""
|
switches |
0:0e018d759a2a
|
164
|
# TODO: table buffering
|
switches |
0:0e018d759a2a
|
165
|
result = None
|
switches |
0:0e018d759a2a
|
166
|
table_pk = '%s_pk'% table
|
switches |
0:0e018d759a2a
|
167
|
query = """SELECT `%s`
|
switches |
0:0e018d759a2a
|
168
|
FROM `%s`
|
switches |
0:0e018d759a2a
|
169
|
WHERE `%s`='%s'"""% (table_pk,
|
switches |
0:0e018d759a2a
|
170
|
table,
|
switches |
0:0e018d759a2a
|
171
|
column,
|
switches |
0:0e018d759a2a
|
172
|
self.escape_string(value))
|
switches |
0:0e018d759a2a
|
173
|
rows = self.select_all(query)
|
switches |
0:0e018d759a2a
|
174
|
if len(rows) == 1:
|
switches |
0:0e018d759a2a
|
175
|
result = rows[0][table_pk]
|
switches |
0:0e018d759a2a
|
176
|
elif len(rows) == 0 and update_db:
|
switches |
0:0e018d759a2a
|
177
|
# Update DB with new value
|
switches |
0:0e018d759a2a
|
178
|
result = self.update_table_entry(table, column, value)
|
switches |
0:0e018d759a2a
|
179
|
return result
|
switches |
0:0e018d759a2a
|
180
|
|
switches |
0:0e018d759a2a
|
181
|
def update_table_entry(self, table, column, value):
|
switches |
0:0e018d759a2a
|
182
|
""" Updates table entry if value in specified column doesn't exist
|
switches |
0:0e018d759a2a
|
183
|
Locks table to perform atomic read + update
|
switches |
0:0e018d759a2a
|
184
|
"""
|
switches |
0:0e018d759a2a
|
185
|
result = None
|
switches |
0:0e018d759a2a
|
186
|
con = self.db_object
|
switches |
0:0e018d759a2a
|
187
|
cur = con.cursor()
|
switches |
0:0e018d759a2a
|
188
|
cur.execute("LOCK TABLES `%s` WRITE"% table)
|
switches |
0:0e018d759a2a
|
189
|
table_pk = '%s_pk'% table
|
switches |
0:0e018d759a2a
|
190
|
query = """SELECT `%s`
|
switches |
0:0e018d759a2a
|
191
|
FROM `%s`
|
switches |
0:0e018d759a2a
|
192
|
WHERE `%s`='%s'"""% (table_pk,
|
switches |
0:0e018d759a2a
|
193
|
table,
|
switches |
0:0e018d759a2a
|
194
|
column,
|
switches |
0:0e018d759a2a
|
195
|
self.escape_string(value))
|
switches |
0:0e018d759a2a
|
196
|
cur.execute(query)
|
switches |
0:0e018d759a2a
|
197
|
rows = cur.fetchall()
|
switches |
0:0e018d759a2a
|
198
|
if len(rows) == 0:
|
switches |
0:0e018d759a2a
|
199
|
query = """INSERT INTO `%s` (%s)
|
switches |
0:0e018d759a2a
|
200
|
VALUES ('%s')"""% (table,
|
switches |
0:0e018d759a2a
|
201
|
column,
|
switches |
0:0e018d759a2a
|
202
|
self.escape_string(value))
|
switches |
0:0e018d759a2a
|
203
|
cur.execute(query)
|
switches |
0:0e018d759a2a
|
204
|
result = cur.lastrowid
|
switches |
0:0e018d759a2a
|
205
|
con.commit()
|
switches |
0:0e018d759a2a
|
206
|
cur.execute("UNLOCK TABLES")
|
switches |
0:0e018d759a2a
|
207
|
return result
|
switches |
0:0e018d759a2a
|
208
|
|
switches |
0:0e018d759a2a
|
209
|
def update_build_id_info(self, build_id, **kw):
|
switches |
0:0e018d759a2a
|
210
|
""" Update additional data inside build_id table
|
switches |
0:0e018d759a2a
|
211
|
Examples:
|
switches |
0:0e018d759a2a
|
212
|
db.update_build_id_info(build_id, _status_fk=self.BUILD_ID_STATUS_COMPLETED, _shuffle_seed=0.0123456789):
|
switches |
0:0e018d759a2a
|
213
|
"""
|
switches |
0:0e018d759a2a
|
214
|
if len(kw):
|
switches |
0:0e018d759a2a
|
215
|
con = self.db_object
|
switches |
0:0e018d759a2a
|
216
|
cur = con.cursor()
|
switches |
0:0e018d759a2a
|
217
|
# Prepare UPDATE query
|
switches |
0:0e018d759a2a
|
218
|
# ["`mtest_build_id_pk`=[value-1]", "`mtest_build_id_name`=[value-2]", "`mtest_build_id_desc`=[value-3]"]
|
switches |
0:0e018d759a2a
|
219
|
set_list = []
|
switches |
0:0e018d759a2a
|
220
|
for col_sufix in kw:
|
switches |
0:0e018d759a2a
|
221
|
assign_str = "`%s%s`='%s'"% (self.TABLE_BUILD_ID, col_sufix, self.escape_string(str(kw[col_sufix])))
|
switches |
0:0e018d759a2a
|
222
|
set_list.append(assign_str)
|
switches |
0:0e018d759a2a
|
223
|
set_str = ', '.join(set_list)
|
switches |
0:0e018d759a2a
|
224
|
query = """UPDATE `%s`
|
switches |
0:0e018d759a2a
|
225
|
SET %s
|
switches |
0:0e018d759a2a
|
226
|
WHERE `mtest_build_id_pk`=%d"""% (self.TABLE_BUILD_ID,
|
switches |
0:0e018d759a2a
|
227
|
set_str,
|
switches |
0:0e018d759a2a
|
228
|
build_id)
|
switches |
0:0e018d759a2a
|
229
|
cur.execute(query)
|
switches |
0:0e018d759a2a
|
230
|
con.commit()
|
switches |
0:0e018d759a2a
|
231
|
|
switches |
0:0e018d759a2a
|
232
|
def insert_test_entry(self, build_id, target, toolchain, test_type, test_id, test_result, test_output, test_time, test_timeout, test_loop, test_extra=''):
|
switches |
0:0e018d759a2a
|
233
|
""" Inserts test result entry to database. All checks regarding existing
|
switches |
0:0e018d759a2a
|
234
|
toolchain names in DB are performed.
|
switches |
0:0e018d759a2a
|
235
|
If some data is missing DB will be updated
|
switches |
0:0e018d759a2a
|
236
|
"""
|
switches |
0:0e018d759a2a
|
237
|
# Get all table FK and if entry is new try to insert new value
|
switches |
0:0e018d759a2a
|
238
|
target_fk = self.get_table_entry_pk(self.TABLE_TARGET, self.TABLE_TARGET + '_name', target)
|
switches |
0:0e018d759a2a
|
239
|
toolchain_fk = self.get_table_entry_pk(self.TABLE_TOOLCHAIN, self.TABLE_TOOLCHAIN + '_name', toolchain)
|
switches |
0:0e018d759a2a
|
240
|
test_type_fk = self.get_table_entry_pk(self.TABLE_TEST_TYPE, self.TABLE_TEST_TYPE + '_name', test_type)
|
switches |
0:0e018d759a2a
|
241
|
test_id_fk = self.get_table_entry_pk(self.TABLE_TEST_ID, self.TABLE_TEST_ID + '_name', test_id)
|
switches |
0:0e018d759a2a
|
242
|
test_result_fk = self.get_table_entry_pk(self.TABLE_TEST_RESULT, self.TABLE_TEST_RESULT + '_name', test_result)
|
switches |
0:0e018d759a2a
|
243
|
|
switches |
0:0e018d759a2a
|
244
|
con = self.db_object
|
switches |
0:0e018d759a2a
|
245
|
cur = con.cursor()
|
switches |
0:0e018d759a2a
|
246
|
|
switches |
0:0e018d759a2a
|
247
|
query = """ INSERT INTO `%s` (`mtest_build_id_fk`,
|
switches |
0:0e018d759a2a
|
248
|
`mtest_target_fk`,
|
switches |
0:0e018d759a2a
|
249
|
`mtest_toolchain_fk`,
|
switches |
0:0e018d759a2a
|
250
|
`mtest_test_type_fk`,
|
switches |
0:0e018d759a2a
|
251
|
`mtest_test_id_fk`,
|
switches |
0:0e018d759a2a
|
252
|
`mtest_test_result_fk`,
|
switches |
0:0e018d759a2a
|
253
|
`mtest_test_output`,
|
switches |
0:0e018d759a2a
|
254
|
`mtest_test_time`,
|
switches |
0:0e018d759a2a
|
255
|
`mtest_test_timeout`,
|
switches |
0:0e018d759a2a
|
256
|
`mtest_test_loop_no`,
|
switches |
0:0e018d759a2a
|
257
|
`mtest_test_result_extra`)
|
switches |
0:0e018d759a2a
|
258
|
VALUES (%d, %d, %d, %d, %d, %d, '%s', %.2f, %.2f, %d, '%s')"""% (self.TABLE_TEST_ENTRY,
|
switches |
0:0e018d759a2a
|
259
|
build_id,
|
switches |
0:0e018d759a2a
|
260
|
target_fk,
|
switches |
0:0e018d759a2a
|
261
|
toolchain_fk,
|
switches |
0:0e018d759a2a
|
262
|
test_type_fk,
|
switches |
0:0e018d759a2a
|
263
|
test_id_fk,
|
switches |
0:0e018d759a2a
|
264
|
test_result_fk,
|
switches |
0:0e018d759a2a
|
265
|
self.escape_string(test_output),
|
switches |
0:0e018d759a2a
|
266
|
test_time,
|
switches |
0:0e018d759a2a
|
267
|
test_timeout,
|
switches |
0:0e018d759a2a
|
268
|
test_loop,
|
switches |
0:0e018d759a2a
|
269
|
self.escape_string(test_extra))
|
switches |
0:0e018d759a2a
|
270
|
cur.execute(query)
|
switches |
0:0e018d759a2a
|
271
|
con.commit()
|