File: fd_test_condition.py

package info (click to toggle)
asterisk-testsuite 0.0.0%2Bsvn.5781-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, stretch
  • size: 18,632 kB
  • sloc: xml: 33,912; python: 32,904; ansic: 1,599; sh: 395; makefile: 170; sql: 17
file content (166 lines) | stat: -rw-r--r-- 6,654 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/usr/bin/env python
"""Test condition for file descriptors

Copyright (C) 2011-2012, Digium, Inc.
Matt Jordan <mjordan@digium.com>

This program is free software, distributed under the terms of
the GNU General Public License Version 2.
"""

import logging

from twisted.internet import defer
from test_conditions import TestCondition

LOGGER = logging.getLogger(__name__)

class FileDescriptor(object):
    """A small object that tracks a file descriptor.

    The object parses a line from the Asterisk CLI command core show fd to
    populate its values
    """

    def __init__(self, line):
        """Constructor

        Keyword Arguments:
        line A raw line received from Asterisk that describes a FD
        """
        self.number = -1
        self.info = "Unknown"

        line = line.strip()
        tokens = line.partition(' ')
        self.number = int(tokens[0])
        self.info = tokens[2].strip()


class FdTestCondition(TestCondition):
    """Base class for the file descriptor pre- and post-test
    checks. This class provides a common mechanism to get the file
    descriptors from Asterisk and populate them in a dictionary for
    tracking
    """

    def __init__(self, test_config):
        """Constructor

        Keyword Arguments:
        test_config The test config object
        """
        super(FdTestCondition, self).__init__(test_config)
        self.file_descriptors = {}
        # core show fd is dependent on DEBUG_FD_LEAKS
        self.add_build_option("DEBUG_FD_LEAKS", "1")

    def get_file_descriptors(self, ast):
        """Get the file descriptors from some instance of Asterisk"""

        def __show_fd_callback(result):
            """Callback when CLI command has finished"""

            lines = result.output
            if 'No such command' in lines:
                return result
            if 'Unable to connect to remote asterisk' in lines:
                return result

            # Trim off the first and last lines
            lines = lines[lines.find('\n'):].strip()
            lines = lines[:lines.find("Asterisk ending")].strip()
            line_tokens = lines.split('\n')
            fds = []
            for line in line_tokens:
                # chan_sip is going to create sockets for the active channels
                # and won't close them until the dialog is reclaimed - 32
                # seconds after the test.  We ignore the UDP socket file
                # descriptors because of this.
                if 'socket(PF_INET,SOCK_DGRAM,"udp")' in line:
                    LOGGER.debug("Ignoring created UDP socket: " + line)
                    continue
                # If we have MALLOC_DEBUG on and are writing out to the mmlog,
                # ignore
                if '__ast_mm_init' in line:
                    LOGGER.debug("Ignoring malloc debug: " + line)
                    continue
                fd = FileDescriptor(line)
                if fd.number != -1:
                    LOGGER.debug("Tracking %d [%s]", fd.number, fd.info)
                    fds.append(fd)
                else:
                    LOGGER.warn("Failed to parse [%s] into file descriptor "
                                "object" % line)
            self.file_descriptors[result.host] = fds

        return ast.cli_exec("core show fd").addCallback(__show_fd_callback)


class FdPreTestCondition(FdTestCondition):
    """The File Descriptor Pre-TestCondition object"""

    def evaluate(self, related_test_condition=None):
        """Evaluate the test condition"""

        def __raise_finished(finished_deferred):
            """Called when all CLI commands have finished"""
            finished_deferred.callback(self)
            return finished_deferred

        # Automatically pass the pre-test condition - whatever file descriptors
        # are currently open are needed by Asterisk and merely expected to exist
        # when the test is finished
        super(FdPreTestCondition, self).pass_check()

        finished_deferred = defer.Deferred()
        exec_list = [super(FdPreTestCondition, self).get_file_descriptors(ast)
            for ast in self.ast]
        defer.DeferredList(exec_list).addCallback(__raise_finished,
                                                  finished_deferred)

        return finished_deferred


class FdPostTestCondition(FdTestCondition):
    """The File Descriptor Post-TestCondition object"""

    def evaluate(self, related_test_condition=None):
        """Evaluate the test condition"""

        def __file_descriptors_obtained(finished_deferred):
            """Callback when all CLI commands have finished"""
            for ast_host in related_test_condition.file_descriptors.keys():
                if not ast_host in self.file_descriptors:
                    super(FdPostTestCondition, self).fail_check(
                        "Asterisk host in pre-test check [%s]"
                        " not found in post-test check" % ast_host)
                else:
                    # Find all file descriptors in pre-check not in post-check
                    for fd in related_test_condition.file_descriptors[ast_host]:
                        if (len([f for f in self.file_descriptors[ast_host] if fd.number == f.number]) == 0):
                            super(FdPostTestCondition, self).fail_check(
                                "Failed to find file descriptor %d [%s] in "
                                "post-test check" % (fd.number, fd.info))
                    # Find all file descriptors in post-check not in pre-check
                    for fd in self.file_descriptors[ast_host]:
                        if (len([f for f in related_test_condition.file_descriptors[ast_host] if fd.number == f.number]) == 0):
                            super(FdPostTestCondition, self).fail_check(
                                "Failed to find file descriptor %d [%s] in "
                                "pre-test check" % (fd.number, fd.info))
            super(FdPostTestCondition, self).pass_check()
            finished_deferred.callback(self)
            return finished_deferred

        if related_test_condition == None:
            msg = "No pre-test condition object provided"
            super(FdPostTestCondition, self).fail_check(msg)
            return

        finished_deferred = defer.Deferred()
        exec_list = [super(FdPostTestCondition, self).get_file_descriptors(ast)
                     for ast in self.ast]
        defer.DeferredList(exec_list).addCallback(__file_descriptors_obtained,
                                                  finished_deferred)
        return finished_deferred