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

tarantool / test-run / 5277688891

pending completion
5277688891

push

github

i-cod
Fix bug when lua script name truncated by dot

Creating a lua diff test with a name containing a dot causes
the name to be parsed incorrectly. Then an attempt is made
to create an tarantool instance with an incorrect name,
resulting in an error. This change fixes the bug.

Fixes #300

759 of 1554 branches covered (48.84%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

2930 of 4328 relevant lines covered (67.7%)

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