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