File: cdr.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 (164 lines) | stat: -rw-r--r-- 5,999 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
#!/usr/bin/env python
"""Asterisk call detail record testing

This module implements an Asterisk CDR parser.

Copyright (C) 2010, Digium, Inc.
Terry Wilson<twilson@digium.com>

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

import unittest
import sys
import astcsv
import logging

LOGGER = logging.getLogger(__name__)

class CDRModule(object):
    """A module that checks a test for expected CDR results"""


    def __init__(self, module_config, test_object):
        """Constructor

        Parameters:
        module_config The yaml loaded configuration for the CDR Module
        test_object A concrete implementation of TestClass
        """
        self.test_object = test_object

        # Build our expected CDR records
        self.cdr_records = {}
        for record in module_config:
            file_name = record['file']
            ast_id = record.get('id') or 0
            if ast_id not in self.cdr_records:
                self.cdr_records[ast_id] = {}
            if file_name not in self.cdr_records[ast_id]:
                self.cdr_records[ast_id][file_name] = []
            for csv_line in record['lines']:
                # Set the record to the default fields, then update with what
                # was passed in to us
                dict_record = dict((k, None) for k in AsteriskCSVCDRLine.fields)
                if csv_line is not None:
                    dict_record.update(csv_line)

                self.cdr_records[ast_id][file_name].append(
                    AsteriskCSVCDRLine(**dict_record))

        # Hook ourselves onto the test object
        test_object.register_stop_observer(self._check_cdr_records)

    def _check_cdr_records(self, callback_param):
        """A deferred callback method that is called by the TestCase
        derived object when all Asterisk instances have stopped

        Parameters:
        callback_param
        """
        LOGGER.debug("Checking CDR records...")
        try:
            self.match_cdrs()
        except:
            LOGGER.error("Exception while checking CDRs: %s" %
                         sys.exc_info()[0])
        return callback_param


    def match_cdrs(self):
        """Called when all instances of Asterisk have exited.  Derived
        classes can override this to provide their own behavior for CDR
        matching.
        """
        expectations_met = True
        for ast_id in self.cdr_records:
            ast_instance = self.test_object.ast[ast_id]
            for file_name in self.cdr_records[ast_id]:
                records = self.cdr_records[ast_id][file_name]
                cdr_expect = AsteriskCSVCDR(records=records)
                cdr_file = AsteriskCSVCDR(filename="%s/%s/cdr-csv/%s.csv" %
                    (ast_instance.base,
                     ast_instance.directories['astlogdir'],
                     file_name))
                if cdr_expect.match(cdr_file):
                    LOGGER.debug("%s.csv: CDR results met expectations" %
                                 file_name)
                else:
                    LOGGER.error("%s.csv: actual did not match expected." %
                                 file_name)
                    expectations_met = False

        self.test_object.set_passed(expectations_met)


class AsteriskCSVCDRLine(astcsv.AsteriskCSVLine):
    """A single Asterisk call detail record"""

    fields = ['accountcode', 'source', 'destination', 'dcontext', 'callerid',
    'channel', 'dchannel', 'lastapp', 'lastarg', 'start', 'answer', 'end',
    'duration', 'billsec', 'disposition', 'amaflags', 'uniqueid', 'userfield']

    def __init__(self, accountcode=None, source=None, destination=None,
            dcontext=None, callerid=None, channel=None, dchannel=None,
            lastapp=None, lastarg=None, start=None, answer=None, end=None,
            duration=None, billsec=None, disposition=None, amaflags=None,
            uniqueid=None, userfield=None):
        """Construct an Asterisk CSV CDR.

        The arguments list definition must be in the same order that the
        arguments appear in the CSV file. They can, of course, be passed to
        __init__ in any order. AsteriskCSVCDR will pass the arguments via a
        **dict.
        """

        astcsv.AsteriskCSVLine.__init__(self,
            AsteriskCSVCDRLine.fields, accountcode=accountcode,
            source=source, destination=destination,
            dcontext=dcontext, callerid=callerid, channel=channel,
            dchannel=dchannel, lastapp=lastapp, lastarg=lastarg, start=start,
            answer=answer, end=end, duration=duration, billsec=billsec,
            disposition=disposition, amaflags=amaflags, uniqueid=uniqueid,
            userfield=userfield)


class AsteriskCSVCDR(astcsv.AsteriskCSV):
    """A representation of an Asterisk CSV CDR file"""

    def __init__(self, filename=None, records=None):
        """Initialize CDR records from an Asterisk cdr-csv file"""

        astcsv.AsteriskCSV.__init__(self, filename, records,
            AsteriskCSVCDRLine.fields, AsteriskCSVCDRLine)


class AsteriskCSVCDRTests(unittest.TestCase):
    """Unit tests for AsteriskCSVCDR"""

    def test_cdr(self):
        """Test the self_test/Master.csv record"""

        cdr = AsteriskCSVCDR("self_test/Master.csv")
        self.assertEqual(len(cdr), 2)
        self.assertTrue(AsteriskCSVCDRLine(duration=7,
            lastapp="hangup").match(cdr[0],
            exact=(True, True)))
        self.assertTrue(cdr[0].match(AsteriskCSVCDRLine(duration=7,
            lastapp="hangup"),
            exact=(True, True)))

        self.assertFalse(cdr[1].match(cdr[0]))
        self.assertFalse(cdr[0].match(cdr[1]))
        self.assertEqual(cdr[0].billsec, "7")

        self.assertTrue(cdr.match(cdr))
        cdr2 = AsteriskCSVCDR("self_test/Master2.csv")
        self.assertFalse(cdr.match(cdr2))


if __name__ == '__main__':
    unittest.main()

# vim:sw=4:ts=4:expandtab:textwidth=79