Switch to unified view

a b/scripts/qiita-test-install
1
#!/usr/bin/env python
2
from os import environ
3
from os.path import join, dirname, abspath, splitext
4
from sys import platform, version as python_version, exit, executable, stdout
5
from unittest import TestLoader, TextTestRunner, TestCase
6
from smtplib import SMTP, SMTP_SSL
7
8
# -----------------------------------------------------------------------------
9
# Copyright (c) 2014--, The Qiita Development Team.
10
#
11
# Distributed under the terms of the BSD 3-clause License.
12
#
13
# The full license is in the file LICENSE, distributed with this software.
14
# -----------------------------------------------------------------------------
15
16
core_dependency_missing_msg = (
17
    '"%s" is missing and is a core requirement, for more information see the '
18
    'Qiita Installation Guide: '
19
    'https://github.com/biocore/qiita/blob/master/INSTALL.md')
20
21
extra_info = (core_dependency_missing_msg + '. It is also possible that you '
22
              'have an old version of this package, if so, please update to '
23
              'the latest.')
24
25
dependency_missing_msg = (
26
    '"%s" is missing but this is _not_ a core requirement, for more '
27
    'information see the Qiita Installation Guide: '
28
    'https://github.com/biocore/qiita/blob/master/INSTALL.md')
29
30
missing_deps_errors = []
31
missing_deps_warnings = []
32
33
try:
34
    from click import __version__ as click_lib_version
35
except ImportError as e:
36
    missing_deps_errors.append((e, extra_info % 'click'))
37
38
try:
39
    from numpy import __version__ as numpy_lib_version
40
except ImportError as e:
41
    missing_deps_errors.append((e, core_dependency_missing_msg % 'NumPy'))
42
43
try:
44
    from pandas import __version__ as pandas_lib_version
45
except ImportError as e:
46
    missing_deps_errors.append((e, core_dependency_missing_msg % 'pandas'))
47
48
try:
49
    from tornado import version as tornado_lib_version
50
except ImportError as e:
51
    missing_deps_errors.append((e, core_dependency_missing_msg % 'tornado'))
52
53
try:
54
    from redis import __version__ as redis_lib_version
55
except ImportError as e:
56
    missing_deps_errors.append((e, core_dependency_missing_msg % 'redis'))
57
58
try:
59
    from toredis import Client as toredis_client
60
    toredis_client()
61
except ImportError as e:
62
    missing_deps_errors.append((e, core_dependency_missing_msg % 'toredis'))
63
64
try:
65
    from redbiom import __version__ as redbiom_lib_version
66
except ImportError as e:
67
    missing_deps_errors.append((e, core_dependency_missing_msg % 'redbiom'))
68
69
try:
70
    from bcrypt import __version__ as bcrypt_lib_version
71
except ImportError as e:
72
    missing_deps_errors.append((e, core_dependency_missing_msg % 'bcrypt'))
73
74
try:
75
    from pyparsing import __version__ as pyparsing_lib_version
76
except ImportError as e:
77
    missing_deps_errors.append((e, core_dependency_missing_msg % 'pyparsing'))
78
79
try:
80
    from networkx import __version__ as networkx_lib_version
81
except ImportError as e:
82
    missing_deps_errors.append((e, core_dependency_missing_msg % 'networkx'))
83
84
try:
85
    from wtforms import __version__ as wtforms_lib_version
86
except ImportError as e:
87
    missing_deps_errors.append((e, core_dependency_missing_msg % 'wtforms'))
88
89
try:
90
    from mock import __version__ as mock_lib_version
91
except ImportError as e:
92
    missing_deps_warnings.append((e, dependency_missing_msg % 'mock'))
93
    mock_lib_version = 'Not installed'
94
95
try:
96
    from psycopg2 import __version__ as psycopg2_lib_version
97
except ImportError as e:
98
    missing_deps_errors.append((e, core_dependency_missing_msg % 'psycopg2'))
99
100
try:
101
    from qiita_core import __version__ as qiita_core_lib_version
102
except ImportError as e:
103
    missing_deps_errors.append((e, core_dependency_missing_msg % 'qiita_core'))
104
105
try:
106
    from qiita_db import __version__ as qiita_db_lib_version
107
except ImportError as e:
108
    missing_deps_errors.append((e, core_dependency_missing_msg % 'qiita_db'))
109
110
try:
111
    from qiita_pet import __version__ as qiita_pet_lib_version
112
except ImportError as e:
113
    missing_deps_errors.append((e, core_dependency_missing_msg % 'qiita_pet'))
114
115
try:
116
    from qiita_ware import __version__ as qiita_ware_lib_version
117
except ImportError as e:
118
    missing_deps_errors.append((e, core_dependency_missing_msg % 'qiita_ware'))
119
120
try:
121
    from qiita_core.configuration_manager import ConfigurationManager
122
    ConfigurationManager()
123
except Exception as e:
124
    missing_deps_errors.append((e, 'You need to add to your enviroment '
125
                                'the Qiita configuration using '
126
                                'QIITA_CONFIG_FP'))
127
128
if missing_deps_errors:
129
    for e, t in missing_deps_errors:
130
        print('%s\n=============' % (t))
131
    exit('Missing core dependencies, can not continue.')
132
133
if missing_deps_warnings:
134
    for e, t in missing_deps_errors:
135
        print('%s\n=============' % (t))
136
137
138
# trick flake8 to not complain about module-level imports not being at the top
139
# of the file. These imports can only really happen if none of the core
140
# dependencies are missing
141
if True:
142
    from qiita_db.sql_connection import TRN
143
    from redis import StrictRedis
144
145
146
class QiitaConfig(TestCase):
147
148
    def setUp(self):
149
        self.config = ConfigurationManager()
150
        try:
151
            with TRN:
152
                TRN.add("SELECT version()")
153
                self.psql_version = TRN.execute_fetchflatten()[0]
154
        except Exception:
155
            self.psql_version = None
156
        try:
157
            r = StrictRedis(
158
                host=self.config.redis_host,
159
                password=self.config.redis_password,
160
                port=self.config.redis_port,
161
                db=self.config.redis_db)
162
            self.redis_version = r.info()['redis_version']
163
        except Exception:
164
            self.redis_version = None
165
166
    def test_pandas_library_version(self):
167
        acceptable_version = (0, 15)
168
        string_acceptable_version = '.'.join(map(str, acceptable_version))
169
        version = tuple(map(int, pandas_lib_version.split('.')))
170
171
        self.assertTrue(acceptable_version <= version,
172
                        'Unsupported pandas version. You have %s but the '
173
                        'minimum required version is %s'
174
                        % (pandas_lib_version, string_acceptable_version))
175
176
    def test_torando_library_version(self):
177
        acceptable_version = (3, 1, 1)
178
        string_acceptable_version = '.'.join(map(str, acceptable_version))
179
        version = tuple(map(int, tornado_lib_version.split('.')))
180
181
        self.assertTrue(acceptable_version <= version,
182
                        'Unsupported tornado version. You have %s but the '
183
                        'minimum required version is %s'
184
                        % (tornado_lib_version, string_acceptable_version))
185
186
    def test_pyparsing_library_version(self):
187
        acceptable_version = (2, 0, 2)
188
        string_acceptable_version = '.'.join(map(str, acceptable_version))
189
        version = tuple(map(int, pyparsing_lib_version.split('.')))
190
191
        self.assertTrue(acceptable_version <= version,
192
                        'Unsupported pyparsing version. You have %s but the '
193
                        'minimum required version is %s'
194
                        % (pyparsing_lib_version, string_acceptable_version))
195
196
    def test_wtforms_library_version(self):
197
        acceptable_version = (2, 0, 1)
198
        string_acceptable_version = '.'.join(map(str, acceptable_version))
199
        version = tuple(map(int, wtforms_lib_version.split('.')))
200
201
        self.assertTrue(acceptable_version <= version,
202
                        'Unsupported WTForms version. You have %s but the '
203
                        'minimum required version is %s'
204
                        % (wtforms_lib_version, string_acceptable_version))
205
206
    def test_postgresql_version(self):
207
        if not self.psql_version:
208
            self.assertTrue(False, 'PostgreSQL not running or configured')
209
210
        acceptable_version = (9, 3, 0)
211
        string_acceptable_version = '.'.join(map(str, acceptable_version))
212
        version = tuple(map(int, self.psql_version.split(' ')[1].split('.')))
213
214
        self.assertTrue(acceptable_version <= version,
215
                        'Unsupported PostgreSQL version. You have %s but the '
216
                        'minimum required version is %s'
217
                        % ('.'.join(map(str, version)),
218
                           string_acceptable_version))
219
220
    def test_redis_version(self):
221
        if not self.redis_version:
222
            self.assertTrue(False, 'redis not running or configured')
223
224
        acceptable_version = (2, 8, 17)
225
        string_acceptable_version = '.'.join(map(str, acceptable_version))
226
        version = tuple(map(int, self.redis_version.split('.')))
227
228
        self.assertTrue(acceptable_version <= version,
229
                        'Unsupported redis version. You have %s but the '
230
                        'minimum required version is %s'
231
                        % ('.'.join(map(str, version)),
232
                           string_acceptable_version))
233
234
    def test_redbiom_version(self):
235
        acceptable_version = (0, 3, 8)
236
        string_acceptable_version = '.'.join(map(str, acceptable_version))
237
        version = tuple(map(int, redbiom_lib_version.split('.')))
238
239
        self.assertTrue(acceptable_version <= version,
240
                        'Unsupported redbiom version. You have %s but the '
241
                        'minimum required version is %s'
242
                        % ('.'.join(map(str, version)),
243
                           string_acceptable_version))
244
245
246
system_info_header = """
247
System information
248
==================
249
"""
250
251
dependency_info_header = """
252
Dependency versions
253
===================
254
"""
255
256
qiita_config_header = """
257
Qiita config
258
============
259
For definitions of these settings and to learn how to configure Qiita, visit:
260
 https://github.com/biocore/qiita/blob/master/INSTALL.md#install
261
"""
262
263
qiita_config_tests_header = """
264
Qiita version and configuration tests
265
=====================================
266
"""
267
268
qiita_plugins_header = """
269
Qiita plugins
270
=============
271
"""
272
273
274
def main():
275
    system_info = [
276
        ("Platform", platform),
277
        ("Python version", python_version.replace('\n', ' ')),
278
        ("Python executable", executable)]
279
    max_len = max([len(e[0]) for e in system_info])
280
    print(system_info_header)
281
    for v in system_info:
282
        print("%*s:\t%s" % (max_len, v[0], v[1]))
283
284
    with TRN:
285
        TRN.add("SELECT current_patch FROM settings")
286
        current_patch = TRN.execute_fetchflatten()[0]
287
    qiita_db_patch_number = splitext(current_patch)[0]
288
289
    # Getting required environment variables
290
    if 'REDBIOM_HOST' in environ:
291
        redbiom_host = environ['REDBIOM_HOST']
292
    else:
293
        redbiom_host = None
294
295
    version_info = [
296
        ('click library version', click_lib_version),
297
        ('numpy library version', numpy_lib_version),
298
        ('pandas library version', pandas_lib_version),
299
        ('tornado library version', tornado_lib_version),
300
        ('redis library version', redis_lib_version),
301
        ('redbiom library version', '%s - host: %s' % (
302
            redbiom_lib_version, redbiom_host)),
303
        ('bcrypt library version', bcrypt_lib_version),
304
        ('pyparsing library version', pyparsing_lib_version),
305
        ('networkX library version', networkx_lib_version),
306
        ('WTForms library version', wtforms_lib_version),
307
        ('mock library version', mock_lib_version),
308
        ('psycopg2 library version', psycopg2_lib_version),
309
        ('Qiita core library version', qiita_core_lib_version),
310
        ('Qiita db library version', qiita_db_lib_version),
311
        ('Qiita db patch number', qiita_db_patch_number),
312
        ('Qiita pet library version', qiita_pet_lib_version),
313
        ('Qiita ware library version', qiita_ware_lib_version)
314
    ]
315
    max_len = max([len(e[0]) for e in version_info])
316
    print(dependency_info_header)
317
    for v in version_info:
318
        print("%*s:\t%s" % (max_len, v[0], v[1]))
319
320
    extra_info = None
321
    qiita_config = ConfigurationManager()
322
    try:
323
        qiita_conf_fp = environ['QIITA_CONFIG_FP']
324
    except KeyError:
325
        qiita_conf_fp = join(dirname(abspath(__file__)),
326
                             'support_files/config_test.cfg')
327
    smtp = SMTP_SSL() if qiita_config.smtp_ssl else SMTP()
328
    smtp.set_debuglevel(False)
329
    try:
330
        smtp.connect(qiita_config.smtp_host, qiita_config.smtp_port)
331
        smtp.verify
332
        send_email = True
333
    except Exception:
334
        send_email = False
335
    ebi_credentials = (qiita_config.ebi_center_name != '' and
336
                       qiita_config.ebi_dropbox_url != '' and
337
                       qiita_config.ebi_organization_prefix != '' and
338
                       qiita_config.ebi_seq_xfer_pass != '' and
339
                       qiita_config.ebi_seq_xfer_url != '' and
340
                       qiita_config.ebi_seq_xfer_user != '')
341
    vamps_credentials = (qiita_config.vamps_pass != '' and
342
                         qiita_config.vamps_url != '' and
343
                         qiita_config.vamps_user != '')
344
    try:
345
        with TRN:
346
            psql_running = True
347
    except Exception:
348
        psql_running = False
349
    try:
350
        StrictRedis(
351
            host=qiita_config.redis_host,
352
            password=qiita_config.redis_password,
353
            port=qiita_config.redis_port,
354
            db=qiita_config.redis_db)
355
        redis_running = True
356
    except Exception:
357
        redis_running = False
358
359
    try:
360
        StrictRedis(
361
             host=qiita_config.redbiom_redis_host,
362
             password=qiita_config.redbiom_redis_password,
363
             port=qiita_config.redbiom_redis_port,
364
             db=qiita_config.redbiom_redis_db)
365
        redbiom_redis_running = True
366
    except Exception:
367
        redbiom_redis_running = False
368
369
    print(qiita_config_header)
370
    qiita_config_info = [
371
        ('QIITA_CONFIG_FP filepath', qiita_conf_fp),
372
        ('Test environment', str(qiita_config.test_environment)),
373
        ('Base URL', qiita_config.base_url),
374
        ('EBI credentials exist', ebi_credentials),
375
        ('VAMPS credentials exist', vamps_credentials),
376
        ('Can the system send emails?', str(send_email) + '. When true, '
377
         'emails could still not be going out due to your network '
378
         'configuration.'),
379
        ('Valid file extensions for upload', ', '.join(
380
         qiita_config.valid_upload_extension)),
381
        ('PostgreSQL is up and configuration can connect?', psql_running),
382
        ('Redis is up and configuracion can connect?',
383
            redis_running if not redis_running else '%s --port %d' % (
384
                redis_running, qiita_config.redis_port)),
385
        ('Redbiom redis is up and configuracion can connect?',
386
            redbiom_redis_running if not redbiom_redis_running else
387
            '%s --port %d' % (redbiom_redis_running,
388
                              qiita_config.redbiom_redis_port)),
389
        ('Extra info', extra_info)
390
    ]
391
    max_len = max([len(e[0]) for e in qiita_config_info])
392
    for v in qiita_config_info:
393
        if v != ('Extra info', None):
394
            print("%*s:\t%s" % (max_len, v[0], v[1]))
395
396
    print(qiita_plugins_header)
397
    if not psql_running:
398
        print("PostgreSQL not running, can't retrieve plugin information")
399
    else:
400
        try:
401
            import qiita_db as qdb
402
            with qdb.sql_connection.TRN:
403
                sql = """SELECT name, version, client_id, client_secret
404
                         FROM qiita.software
405
                            JOIN qiita.oauth_software USING (software_id)
406
                            JOIN qiita.oauth_identifiers USING (client_id)"""
407
                qdb.sql_connection.TRN.add(sql)
408
                res = qdb.sql_connection.TRN.execute_fetchindex()
409
                for name, version, client_id, client_secret in res:
410
                    print("Plugin name: %s" % name)
411
                    print("\tVersion: %s" % version)
412
                    print("\tClient id: %s" % client_id)
413
                    print("\tClient secret: %s" % client_secret)
414
        except Exception as e:
415
            print("An error occurred while retrieving plugin information: %s"
416
                  % str(e))
417
418
    print(qiita_config_tests_header)
419
    suite = TestLoader().loadTestsFromTestCase(QiitaConfig)
420
    TextTestRunner(stream=stdout, verbosity=1).run(suite)
421
422
423
if __name__ == "__main__":
424
    main()