• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / test-run / 3685840692

pending completion
3685840692

push

github

viacheslav.kirichenko
ci: update test matrix

749 of 1514 branches covered (49.47%)

Branch coverage included in aggregate %.

2893 of 4242 relevant lines covered (68.2%)

0.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

44.76
/lib/preprocessor.py
1
import os
1✔
2
import shlex
1✔
3
import signal
1✔
4
import sys
1✔
5
from collections import deque
1✔
6

7
import yaml
1✔
8
from gevent import socket
1✔
9

10
from lib.admin_connection import AdminAsyncConnection
1✔
11
from lib.colorer import color_log
1✔
12
from lib.utils import signum
1✔
13
from lib.utils import signame
1✔
14
from lib.utils import integer_types
1✔
15
from lib.utils import string_types
1✔
16

17

18
class Namespace(object):
1✔
19
    pass
1✔
20

21

22
class LuaPreprocessorException(Exception):
1✔
23
    """ Raised when evaluation of a test-run command failed.
24

25
        This exception is displayed as QA notice on the terminal.
26

27
        A Lua error is raised in a test code. The raised object is
28
        a string with given error message.
29

30
        All other errors that are raised during a command
31
        evaluation are considered as show stoppers and lead to
32
        stop execution of a test. KeyboardInterrupt and
33
        TarantoolStartError stops testing at all, see
34
        inspector.py.
35
    """
36

37
    def __init__(self, val):
1✔
38
        super(LuaPreprocessorException, self).__init__()
×
39
        self.value = val
×
40

41
    def __str__(self):
1✔
42
        return self.value
×
43

44

45
class TestState(object):
1✔
46
    def __init__(self, suite_ini, default_server, create_server, params={},
1✔
47
                 **kwargs):
48
        self.delimiter = ''
1✔
49
        self.suite_ini = suite_ini
1✔
50
        self.environ = Namespace()
1✔
51
        self.operation = False
1✔
52
        self.create_server = create_server
1✔
53
        self.servers = {'default': default_server}
1✔
54
        self.connections = {}
1✔
55
        self.run_params = params
1✔
56
        if default_server is not None:
1✔
57
            self.connections = {'default': default_server.admin}
1✔
58
            # curcon is an array since we may have many connections
59
            self.curcon = [self.connections['default']]
1✔
60
            nmsp = Namespace()
1✔
61
            setattr(nmsp, 'admin', default_server.admin.uri)
1✔
62
            setattr(nmsp, 'listen', default_server.listen_uri)
1✔
63
            setattr(self.environ, 'default', nmsp)
1✔
64
        # for propagating 'current_test' to non-default servers
65
        self.default_server_no_connect = kwargs.get(
1✔
66
            'default_server_no_connect')
67

68
    def parse_preprocessor(self, string):
1✔
69
        token_store = deque()
1✔
70
        lexer = shlex.shlex(string)
1✔
71
        lexer.commenters = []
1✔
72
        token = lexer.get_token()
1✔
73
        if not token:
1!
74
            return
×
75
        if token == 'setopt':
1✔
76
            option = lexer.get_token()
1✔
77
            if not option:
1!
78
                raise LuaPreprocessorException(
×
79
                    "Wrong token for setopt: expected option name")
80
            value = lexer.get_token()
1✔
81
            if not value:
1!
82
                raise LuaPreprocessorException(
×
83
                    "Wrong token for setopt: expected option value")
84
            return self.options(option, value)
1✔
85
        elif token == 'eval':
1!
86
            name = lexer.get_token()
×
87
            expr = lexer.get_token()
×
88

89
            # token format: eval <server name> "<expr>"
90
            return self.lua_eval(name, expr[1:-1])
×
91
        elif token == 'switch':
1!
92
            server = lexer.get_token()
×
93
            return self.switch(server)
×
94
        elif token == 'config':
1!
95
            lexer.get_token()
×
96
            return self.run_params
×
97
        token_store.append(token)
1✔
98
        token = lexer.get_token()
1✔
99
        if token == 'server':
1!
100
            stype = token_store.popleft()
1✔
101
            sname = lexer.get_token()
1✔
102
            if not sname:
1!
103
                raise LuaPreprocessorException(
×
104
                    "Wrong token for server: expected name")
105
            options = {}
1✔
106
            temp = lexer.get_token()
1✔
107
            if not temp:
1✔
108
                pass
1✔
109
            elif temp == 'with':
1!
110
                while True:
111
                    k = lexer.get_token()
1✔
112
                    if not k:
1✔
113
                        break
1✔
114
                    v = lexer.get_token()
1✔
115
                    if v == '=':
1!
116
                        v = lexer.get_token()
1✔
117
                    options[k] = v
1✔
118
                    lexer.get_token()
1✔
119
            else:
120
                raise LuaPreprocessorException(
×
121
                    "Wrong token for server: expected 'with', got {0}".format(
122
                        repr(temp)))
123
            return self.server(stype, sname, options)
1✔
124
        elif token == 'connection':
×
125
            ctype = token_store.popleft()
×
126
            cname = [lexer.get_token()]
×
127
            if not cname[0]:
×
128
                raise LuaPreprocessorException(
×
129
                    "Wrong token for connection: expected name")
130
            cargs = None
×
131
            temp = lexer.get_token()
×
132
            if temp == 'to':
×
133
                cargs = lexer.get_token()
×
134
            elif temp == ',':
×
135
                while True:
136
                    a = lexer.get_token()
×
137
                    if not a:
×
138
                        break
×
139
                    if a == ',':
×
140
                        continue
×
141
                    cname.append(a)
×
142
            elif temp:
×
143
                raise LuaPreprocessorException(
×
144
                    ("Wrong token for server: expected 'to' or ',', " +
145
                     "got {0}").format(repr(temp)))
146
            return self.connection(ctype, cname, cargs)
×
147
        elif token == 'filter':
×
148
            ftype = token_store.popleft()
×
149
            ref = None
×
150
            ret = None
×
151
            temp = lexer.get_token()
×
152
            if temp:
×
153
                ref = temp
×
154
                if not temp:
×
155
                    raise LuaPreprocessorException(
×
156
                        "Wrong token for filter: expected filter1")
157
                if lexer.get_token() != 'to':
×
158
                    raise LuaPreprocessorException(
×
159
                        ("Wrong token for filter: expected 'to', " +
160
                         "got {0}").format(repr(temp)))
161
                temp = lexer.get_token()
×
162
                if not temp:
×
163
                    raise LuaPreprocessorException(
×
164
                        "Wrong token for filter: expected filter2")
165
                ret = temp
×
166
            return self.filter(ftype, ref, ret)
×
167
        elif token == 'variable':
×
168
            ftype = token_store.popleft()
×
169
            ref = lexer.get_token()
×
170
            temp = lexer.get_token()
×
171
            if temp != 'to':
×
172
                raise LuaPreprocessorException(
×
173
                    "Wrong token for filter: exptected 'to', got {0}".format(
174
                        repr(temp)))
175
            ret = lexer.get_token()
×
176
            return self.variable(ftype, ref, ret)
×
177
        else:
178
            raise LuaPreprocessorException(
×
179
                "Wrong command: {0}".format(repr(lexer.instream.getvalue())))
180

181
    def options(self, key, value):
1✔
182
        if key == 'delimiter':
1!
183
            self.delimiter = value[1:-1]
1✔
184
        else:
185
            raise LuaPreprocessorException(
×
186
                "Wrong option: {0}".format(repr(key)))
187

188
    def server_start(self, ctype, sname, opts):
1✔
189
        if sname not in self.servers:
1!
190
            raise LuaPreprocessorException(
×
191
                'Can\'t start nonexistent server {0}'.format(repr(sname)))
192
        wait = True
1✔
193
        if 'wait' in opts and opts['wait'] == 'False':
1!
194
            wait = False
×
195
        wait_load = True
1✔
196
        if 'wait_load' in opts and opts['wait_load'] == 'False':
1!
197
            wait_load = False
×
198
        args = []
1✔
199
        if 'args' in opts:
1!
200
            args = opts['args'][1:-1].split(' ')
×
201

202
        crash_expected = 'crash_expected' in opts and \
1✔
203
            opts['crash_expected'] == 'True'
204
        crash_occured = False
1✔
205
        try:
1✔
206
            if crash_expected:
1!
207
                # disable crash detector
208
                self.servers[sname].crash_expected = True
×
209
            self.servers[sname].start(silent=True, rais=True, wait=wait,
1✔
210
                                      wait_load=wait_load, args=args)
211
        except Exception as e:
×
212
            crash_occured = True
×
213
            if not (crash_expected and
×
214
                    e.__class__.__name__ == 'TarantoolStartError'):
215
                raise
×
216
        if not crash_occured:
1!
217
            self.connections[sname] = self.servers[sname].admin
1✔
218
            try:
1✔
219
                self.connections[sname]('return true', silent=True)
1✔
220
            except socket.error:
×
221
                LuaPreprocessorException(
×
222
                    'Can\'t start server {0}'.format(repr(sname)))
223
        return not crash_occured
1✔
224

225
    def server_stop(self, ctype, sname, opts):
1✔
226
        if sname not in self.servers:
1!
227
            raise LuaPreprocessorException(
×
228
                'Can\'t stop nonexistent server {0}'.format(repr(sname)))
229
        if not self.servers[sname].status:
1!
230
            raise LuaPreprocessorException(
×
231
                'Attempt to stop already stopped server {0}'.format(repr(sname)))
232
        self.connections[sname].disconnect()
1✔
233
        self.connections.pop(sname)
1✔
234
        if 'signal' in opts:
1!
235
            # convert to an integer if a number is passed, leave a string
236
            # otherwise
237
            try:
×
238
                signal = int(opts['signal'])
×
239
            except ValueError:
×
240
                signal = opts['signal']
×
241
            self.servers[sname].stop(silent=True, signal=signum(signal))
×
242
        else:
243
            # use default signal
244
            self.servers[sname].stop(silent=True)
1✔
245

246
    def server_create(self, ctype, sname, opts):
1✔
247
        if sname in self.servers:
1!
248
            raise LuaPreprocessorException(
×
249
                'Server {0} already exists'.format(repr(sname)))
250
        temp = self.create_server()
1✔
251
        temp.name = sname
1✔
252
        if 'need_init' in opts:
1!
253
            temp.need_init = True if opts['need_init'] == 'True' else False
×
254
        if 'script' in opts:
1!
255
            temp.script = opts['script'][1:-1]
1✔
256
        if 'lua_libs' in opts:
1!
257
            temp.lua_libs = opts['lua_libs'][1:-1].split(' ')
×
258
        temp.rpl_master = None
1✔
259
        if 'rpl_master' in opts:
1!
260
            temp.rpl_master = self.servers[opts['rpl_master']]
1✔
261
        temp.vardir = self.suite_ini['vardir']
1✔
262
        temp.use_unix_sockets_iproto = \
1✔
263
            self.suite_ini['use_unix_sockets_iproto']
264
        temp.inspector_port = int(self.suite_ini.get(
1✔
265
            'inspector_port', temp.DEFAULT_INSPECTOR
266
        ))
267
        if self.default_server_no_connect:
1!
268
            temp.current_test = self.default_server_no_connect.current_test
×
269
        elif self.servers['default']:
1!
270
            temp.current_test = self.servers['default'].current_test
1✔
271
        temp.install(silent=True)
1✔
272
        self.servers[sname] = temp
1✔
273
        if 'workdir' in opts:
1!
274
            copy_from = opts['workdir']
×
275
            copy_to = self.servers[sname].name
×
276
            os.system('rm -rf %s/%s' % (
×
277
                self.servers[sname].vardir, copy_to
278
            ))
279
            os.system('cp -r %s %s/%s' % (
×
280
                copy_from,
281
                self.servers[sname].vardir,
282
                copy_to
283
            ))
284
        nmsp = Namespace()
1✔
285
        setattr(nmsp, 'admin', temp.admin.uri)
1✔
286
        setattr(nmsp, 'listen', temp.listen_uri)
1✔
287
        if temp.rpl_master:
1!
288
            setattr(nmsp, 'master', temp.rpl_master.iproto.uri)
1✔
289
        setattr(self.environ, sname, nmsp)
1✔
290
        if 'return_listen_uri' in opts and opts['return_listen_uri'] == 'True':
1!
291
            return self.servers[sname].listen_uri
×
292

293
    def server_deploy(self, ctype, sname, opts):
1✔
294
        self.servers[sname].install()
×
295

296
    def server_cleanup(self, ctype, sname, opts):
1✔
297
        if sname not in self.servers:
1!
298
            raise LuaPreprocessorException(
×
299
                'Can\'t cleanup nonexistent server {0}'.format(repr(sname)))
300
        self.servers[sname].cleanup()
1✔
301
        if sname != 'default':
1!
302
            if hasattr(self.environ, sname):
1!
303
                delattr(self.environ, sname)
1✔
304
        else:
305
            self.servers[sname].install(silent=True)
×
306

307
    def server_delete(self, ctype, sname, opts):
1✔
308
        if sname not in self.servers:
1!
309
            raise LuaPreprocessorException(
×
310
                'Can\'t cleanup nonexistent server {0}'.format(repr(sname)))
311
        self.servers[sname].cleanup()
1✔
312
        if sname != 'default':
1!
313
            if hasattr(self.environ, sname):
1!
314
                delattr(self.environ, sname)
×
315
            del self.servers[sname]
1✔
316

317
    def switch(self, server):
1✔
318
        self.lua_eval(server, "env=require('test_run')", silent=True)
×
319
        self.lua_eval(
×
320
            server, "test_run=env.new()", silent=True
321
        )
322
        return self.connection('set', [server, ], None)
×
323

324
    def server_restart(self, ctype, sname, opts):
1✔
325
        # self restart from lua with proxy
326
        if 'proxy' not in self.servers:
×
327
            self.server_create(
×
328
                'create', 'proxy', {'script': '"box/proxy.lua"'}
329
            )
330
        self.server_start('start', 'proxy', {})
×
331
        self.switch('proxy')
×
332

333
        # restart real server and switch back
334
        self.server_stop(ctype, sname, opts)
×
335
        if 'cleanup' in opts:
×
336
            self.server_cleanup(ctype, sname, opts)
×
337
            self.server_deploy(ctype, sname, opts)
×
338
        try:
×
339
            self.server_start(ctype, sname, opts)
×
340
            self.switch(sname)
×
341
        finally:
342
            # remove proxy
343
            self.server_stop('stop', 'proxy', {})
×
344

345
    def server_get_iproto_uri(self, ctype, sname, opts):
1✔
346
        return self.servers[sname].iproto.uri
×
347

348
    def server(self, ctype, sname, opts):
1✔
349
        attr = 'server_%s' % ctype
1✔
350
        if hasattr(self, attr):
1!
351
            return getattr(self, attr)(ctype, sname, opts)
1✔
352
        else:
353
            raise LuaPreprocessorException(
×
354
                'Unknown command for server: %s' % ctype
355
            )
356

357
    def connection(self, ctype, cnames, sname):
1✔
358
        # we always get a list of connections as input here
359
        cname = cnames[0]
×
360
        if ctype == 'create':
×
361
            if sname not in self.servers:
×
362
                raise LuaPreprocessorException(
×
363
                    ('Can\'t create connection to nonexistent server ' +
364
                     '{0}').format(repr(sname)))
365
            if cname in self.connections:
×
366
                raise LuaPreprocessorException(
×
367
                    'Connection {0} already exists'.format(repr(cname)))
368
            self.connections[cname] = AdminAsyncConnection(
×
369
                'localhost', self.servers[sname].admin.port)
370
            self.connections[cname].connect()
×
371
        elif ctype == 'drop':
×
372
            if cname not in self.connections:
×
373
                raise LuaPreprocessorException(
×
374
                    'Can\'t drop nonexistent connection {0}'.format(
375
                        repr(cname)))
376
            self.connections[cname].disconnect()
×
377
            self.connections.pop(cname)
×
378
        elif ctype == 'set':
×
379
            for i in cnames:
×
380
                if i not in self.connections:
×
381
                    raise LuaPreprocessorException(
×
382
                        'Can\'t set nonexistent connection {0}'.format(
383
                            repr(cname)))
384
            self.curcon = [self.connections[i] for i in cnames]
×
385
        else:
386
            raise LuaPreprocessorException(
×
387
                'Unknown command for connection: {0}'.format(repr(ctype)))
388

389
    def filter(self, ctype, ref, ret):
1✔
390
        if ctype == 'push':
×
391
            sys.stdout.push_filter(ref[1:-1], ret[1:-1])
×
392
        elif ctype == 'pop':
×
393
            sys.stdout.pop_filter()
×
394
        elif ctype == 'clear':
×
395
            sys.stdout.clear_all_filters()
×
396
        else:
397
            raise LuaPreprocessorException(
×
398
                "Wrong command for filters: {0}".format(repr(ctype)))
399

400
    def lua_eval(self, name, expr, silent=True):
1✔
401
        if name not in self.servers:
×
402
            raise LuaPreprocessorException('Attempt to evaluate a command on ' +
×
403
                                           'the nonexistent server {0}'.format(
404
                                            repr(name)))
405
        self.servers[name].admin.reconnect()
×
406
        result = self.servers[name].admin(
×
407
            '%s%s' % (expr, self.delimiter), silent=silent
408
        )
409
        result = yaml.safe_load(result)
×
410
        if not result:
×
411
            result = []
×
412
        return result
×
413

414
    def variable(self, ctype, ref, ret):
1✔
415
        if ctype == 'set':
×
416
            self.curcon[0].reconnect()
×
417
            result = eval(ret[1:-1], {}, self.environ.__dict__)
×
418
            if isinstance(result, integer_types):
×
419
                cmd = '{0}={1}'.format(ref, result)
×
420
            elif isinstance(result, string_types):
×
421
                cmd = '{0}="{1}"'.format(ref, result)
×
422
            else:
423
                raise LuaPreprocessorException(
×
424
                    "Wrong result type for variable {0}".format(ref))
425
            self.curcon[0](cmd, silent=True)
×
426
        else:
427
            raise LuaPreprocessorException(
×
428
                "Wrong command for variables: {0}".format(repr(ctype)))
429

430
    def __call__(self, string):
1✔
431
        string = string[3:].strip()
×
432
        self.parse_preprocessor(string)
×
433

434
    def stop_nondefault(self, signal=signal.SIGTERM):
1✔
435
        names = [k for k in self.servers.keys() if k != 'default']
1✔
436
        color_log('DEBUG: Stop non-default servers using '
1✔
437
                  'signal {} ({}): {}\n'.format(signal, signame(signal),
438
                                                names), schema='info')
439
        if sys.stdout.__class__.__name__ == 'FilteredStream':
1!
440
            sys.stdout.clear_all_filters()
1✔
441
        for k, v in self.servers.items():
1✔
442
            # don't stop the default server
443
            if k == 'default':
1!
444
                continue
1✔
445
            v.stop(silent=True, signal=signal)
×
446
            if k in self.connections:
×
447
                self.connections[k].disconnect()
×
448
                self.connections.pop(k)
×
449

450
    def cleanup_nondefault(self):
1✔
451
        names = [k for k in self.servers.keys() if k != 'default']
1✔
452
        color_log('DEBUG: Cleanup non-default servers: {}\n'.format(names),
1✔
453
                  schema='info')
454
        for k, v in self.servers.items():
1✔
455
            # don't cleanup the default server
456
            if k == 'default':
1!
457
                continue
1✔
458
            v.cleanup()
×
459

460
    def kill_current_test(self):
1✔
461
        if self.servers['default']:
×
462
            self.servers['default'].kill_current_test()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc