xref: /aosp_15_r20/external/autotest/client/cros/cellular/sms.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# Lint as: python2, python3
2# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6from __future__ import absolute_import
7from __future__ import division
8from __future__ import print_function
9
10import dbus, logging
11
12from six.moves import zip
13
14from autotest_lib.client.common_lib import error
15
16sample = {
17    'pdu' :
18      '07914140540510F0040B916171056429F500001190804181106904D4F29C0E',
19    'parsed' :
20      {'text' : 'Test',
21       'number' : '+16175046925',
22       'timestamp' : '110908141801-04',
23       'smsc' : '+14044550010'
24       }
25    }
26
27sample_multipart = {
28    'pdu' :
29      ['07912160130320F8440B916171056429F5000011909161037469A0050003920201A9'
30       'E5391DF43683E6EF7619C47EBBCF207A194F0789EB74D03D4D47BFEB7450D89D0791'
31       'D366737A5C67D3416374581E1ED3CBF23928ED1EB3EBE43219947683E8E832A85D9E'
32       'CFC3E7B20B4445A7E72077B94C9E83E86F90B80C7ADBCB72101D5D06B1CBEE331D0D'
33       'A2A3E5E539FACD2683CC6F39888E2E83D8EF71980D9ABFCDF47B585E06D1DF',
34       '07912160130320F5440B916171056429F50000119091610384691505000392020241'
35       'E437888E2E83E670769AEE02'],
36    'parsed' :
37      {'text' : 'Test of some long text but without any difficult characters'
38       ' included in the message. This needs to be over the length threshold'
39       ' for the local software to do the split.',
40       'number' : '+16175046925',
41       'timestamp' : '110919163047-04',
42       'smsc' : '+12063130028'
43       }
44    }
45
46
47class SmsStore(object):
48    '''SMS content management - this maintains an internal model of the
49    index->PDU mapping that the fakemodem program should be returning so
50    that tests can add and remove individual PDUs and handles generating
51    the correct set of responses, including the complete SMS list.
52    '''
53
54    def __init__(self, fakemodem):
55        self.fakemodem = fakemodem
56        self.smsdict = {}
57        self.fakemodem.SetResponse('\+CMGR=', '', '+CMS ERROR: 321')
58        self.fakemodem.SetResponse('\+CMGD=', '', '+CMS ERROR: 321')
59        self._sms_regen_list()
60
61    def sms_insert(self, index, pdu):
62        '''Add a SMS to the fake modem's list.'''
63        smsc_len = int(pdu[0:1], 16)
64        mlen = len(pdu)/2 - smsc_len - 1
65
66        self.fakemodem.RemoveResponse('\+CMGD=')
67        self.fakemodem.RemoveResponse('\+CMGR=')
68        self.fakemodem.SetResponse('\+CMGD=%d' % (index), '', '')
69        self.fakemodem.SetResponse('\+CMGR=%d' % (index),
70                                   '+CMGR: 1,,%d\r\n%s' % (mlen, pdu), '')
71        self.fakemodem.SetResponse('\+CMGR=', '', '+CMS ERROR: 321')
72        self.fakemodem.SetResponse('\+CMGD=', '', '+CMS ERROR: 321')
73
74        self.smsdict[index] = pdu
75        self._sms_regen_list()
76
77    def sms_receive(self, index, pdu):
78        '''Add a SMS to the fake modem's list, like sms_insert(), and generate
79        an unsolicited new-sms message.'''
80        self.sms_insert(index, pdu)
81        self.fakemodem.SendUnsolicited('+CMTI: "ME",%d'%(index))
82
83    def sms_remove(self, index):
84        '''Remove a SMS from the fake modem's list'''
85        self.fakemodem.RemoveResponse('\+CMGR=%d' % (index))
86        self.fakemodem.RemoveResponse('\+CMGD=%d' % (index))
87        del self.smsdict[index]
88        self._sms_regen_list()
89
90    def _sms_regen_list(self):
91        response = ''
92        keys = list(self.smsdict.keys())
93        keys.sort()
94        for i in keys:
95            pdu = self.smsdict[i]
96            smsc_len = int(pdu[0:1],16)
97            mlen = len(pdu)/2 - smsc_len - 1
98            response = response + '+CMGL: %d,1,,%d\r\n%s\r\n' % (i, mlen, pdu)
99        self.fakemodem.SetResponse('\+CMGL=4', response, '')
100
101
102class SmsTest(object):
103    def __init__(self, gsmsms):
104        self.gsmsms = gsmsms
105
106    def compare(self, expected, got):
107        '''Compare two SMS dictionaries, discounting the index number if
108        not specified in the first.'''
109        if expected == got:
110            return True
111        if 'index' in expected:
112            return False
113        if 'index' not in got:
114            return False
115        got = dict(got)
116        del got['index']
117        return expected == got
118
119    def compare_list(self, expected_list, got_list):
120        if len(expected_list) != len(got_list):
121            return False
122        # There must be a more Pythonic way to do this
123        for (expected,got) in zip(expected_list, got_list):
124            if self.compare(expected, got) == False:
125                return False
126        return True
127
128    def test_get(self, index, expected):
129        try:
130            sms = self.gsmsms.Get(index)
131        except dbus.DBusException as db:
132            if expected is not None:
133                raise
134            return
135
136        if expected is None:
137            logging.info('Got %s' % sms)
138            raise error.TestFail('SMS.Get(%d) succeeded unexpectedly' %
139                                 index)
140        if self.compare(expected, sms) == False:
141            logging.info('Got %s, expected %s' % (sms, expected))
142            raise error.TestFail('SMS.Get(%d) did not match expected values' %
143                                 index)
144
145    def test_delete(self, index, expected_success):
146        try:
147            self.gsmsms.Delete(index)
148            if expected_success == False:
149                raise error.TestFail('SMS.Delete(%d) succeeded unexpectedly' %
150                                     index)
151        except dbus.DBusException as db:
152            if expected_success:
153                raise
154
155    def test_list(self, expected_list):
156        sms_list = self.gsmsms.List()
157        if self.compare_list(expected_list, sms_list) == False:
158            logging.info('Got %s, expected %s' % (sms_list, expected_list))
159            raise error.TestFail('SMS.List() did not match expected values')
160
161    def test_has_none(self):
162        '''Test that the SMS interface has no messages.'''
163        self.test_list([])
164        self.test_get(1, None)
165        self.test_delete(1, False)
166        self.test_delete(2, False)
167
168    def test_has_one(self, parsed_sms):
169        '''Test that the SMS interface has exactly one message at index 1
170        As a side effect, deletes the message.'''
171        self.test_list([parsed_sms])
172        self.test_get(1, parsed_sms)
173        self.test_get(2, None)
174        self.test_delete(2, False)
175        self.test_delete(1, True)
176