Exemplo n.º 1
0
Arquivo: api.py Projeto: dmaclay/vumi
class ConversationHandlerTestCase(TestCase):

    fixtures = ['user_set']

    def setUp(self):
        self.client = APIClient()
        self.client.login(username='******', password='******')
        # create the user we need to be authorized
        self.user = User.objects.get(username='******')
        # load the yaml data
        fp = open(os.path.join(settings.APP_ROOT, 'webapp', 'api',
                               'test_data', 'devquiz.yaml'), 'r')
        self.yaml_conversation = ''.join(fp.readlines())

    def tearDown(self):
        pass

    def test_creation_of_conversation(self):
        """
        Conversations should be able to be created by POSTing to the api
        """
        resp = self.client.post(reverse('api:conversation'),
                                self.yaml_conversation,
                                content_type="application/x-yaml")
        self.assertContains(resp, 'Created', status_code=201)
        resp = self.client.get(reverse('api:conversation'))
        self.assertEquals(resp.status_code, 405)
Exemplo n.º 2
0
class OperaSentSMSStatusTestCase(TestCase):

    fixtures = ["user_set", "opera_sentsms_set"]

    def setUp(self):
        self.client = APIClient()
        self.client.login("api", "password")
        self.user = User.objects.get(username="******")

    def tearDown(self):
        pass

    def test_sms_status_list_since(self):
        """
        Sorry this test needs some explanation. In the SentSMS model I'm using
        Django's `auto_now` and `auto_now_add` options to automatically 
        timestamp the `created_at` and `updated_at` values. Downside of this
        is that you now no longer can set these values from the code. The 
        fixture has a `SentSMS` entry from 2009. I'm using that date to make
        sure the `since` parameter gives us back that entry as well instead
        of only the most recent 50 ones (which I create manually in this test).
        """
        january_2009 = datetime(2009, 01, 01, 0, 0, 0)
        new_smss = mock_sent_messages(self.user, count=50)
        resp = self.client.get(reverse("api:opera:sms-status-list"), {"since": january_2009})
        from django.utils import simplejson

        data = simplejson.loads(resp.content)
        self.assertEquals(len(data), 51)  # respects the `since` parameter
        # overriding the `limit` parameter.
        # On top of the 50 newly created
        # entries it should also return the
        # 51st entry which is one from 2009
        # in the fixtures file.
        self.assertEquals(resp.status_code, 200)

    def test_single_status(self):
        sent_sms = SentSMS.objects.latest("created_at")
        resp = self.client.get(reverse("api:opera:sms-status", kwargs={"sms_id": sent_sms.pk}))
        from django.utils import simplejson

        json_sms = simplejson.loads(resp.content)
        self.assertEquals(json_sms["to_msisdn"], sent_sms.to_msisdn)
        self.assertEquals(json_sms["from_msisdn"], sent_sms.from_msisdn)
        self.assertEquals(json_sms["message"], sent_sms.message)
        self.assertEquals(json_sms["transport_status"], sent_sms.transport_status)
        self.assertEquals(resp.status_code, 200)

    def test_multiple_statuses(self):
        smss = mock_sent_messages(self.user, count=10)
        sms_ids = map(lambda sms: int(sms.pk), smss)
        sms_ids.sort()
        resp = self.client.get(reverse("api:opera:sms-status-list"), {"id": sms_ids})
        from django.utils import simplejson

        json_smss = simplejson.loads(resp.content)
        json_sms_ids = map(lambda sms: int(sms["id"]), json_smss)
        json_sms_ids.sort()
        self.assertEquals(sms_ids, json_sms_ids)
        self.assertEquals(resp.status_code, 200)
Exemplo n.º 3
0
Arquivo: api.py Projeto: dmaclay/vumi
class BaseSMSHandlerTestCase(TestCase):

    fixtures = ['user_set']

    def setUp(self):
        self.client = APIClient()
        self.client.login(username='******', password='******')
        # get the user
        self.user = User.objects.get(username='******')
        # make sure the transport's set
        profile = self.user.get_profile()
        profile.transport = Transport.objects.create(name='Clickatell')
        profile.save()

    def test_sms_sending(self):
        self.assertEquals(SentSMS.objects.count(), 0)
        resp = self.client.post(reverse('api:sms-send'), {
            'to_msisdn': '27123456789',
            'from_msisdn': '27123456789',
            'message': 'yebo',
        })
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(SentSMS.objects.count(), 1)
        self.assertEquals(SentSMSBatch.objects.count(), 1)
        batch = SentSMSBatch.objects.all()[0]
        self.assertEquals(batch.sentsms_set.count(), 1)

    def test_batch_sms_sending(self):
        self.assertEquals(SentSMS.objects.count(), 0)
        resp = self.client.post(reverse('api:sms-send'), {
            'to_msisdn': ['27123456780', '27123456781', '27123456782'],
            'from_msisdn': '27123456789',
            'message': 'yebo',
        })
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(SentSMS.objects.count(), 3)
        self.assertEquals(SentSMSBatch.objects.count(), 1)
        batch = SentSMSBatch.objects.all()[0]
        self.assertEquals(batch.sentsms_set.count(), 3)

    def test_template_sms_sending(self):
        self.assertEquals(SentSMS.objects.count(), 0)
        resp = self.client.post(reverse('api:sms-template-send'), {
            'to_msisdn': ['27123456780', '27123456781', '27123456782'],
            'template_first_name': ['Name 1', 'Name 2', 'Name 3'],
            'template_last_name': ['Surname 1', 'Surname 2', 'Surname 3'],
            'from_msisdn': '27123456789',
            'template': 'Hi {{first_name}} {{last_name}}',
        })
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(SentSMS.objects.count(), 3)
        self.assertEquals(SentSMSBatch.objects.count(), 1)
        batch = SentSMSBatch.objects.all()[0]
        self.assertEquals(batch.sentsms_set.count(), 3)
Exemplo n.º 4
0
class TechsysSMSHandlerTestCase(TestCase):
    
    fixtures = ['user_set']
    
    def setUp(self):
        self.client = APIClient()
        self.client.login(username='******', password='******')
        # create the user we need to be authorized
        self.user = User.objects.get(username='******')
    
    def test_sms_receipts(self):
        """
        E-Scape currently doesn't send us sms receipts, shouldn't respond
        """
        resp = self.client.post(reverse('api:techsys:sms-receipt'))
        self.assertEquals(resp.status_code, 405)
        resp = self.client.get(reverse('api:techsys:sms-receipt'))
        self.assertEquals(resp.status_code, 405)
    
    def test_sms_sending(self):
        self.assertEquals(SentSMS.objects.count(), 0)
        resp = self.client.post(reverse('api:techsys:sms-send'), {
            'to_msisdn': '27123456789',
            'from_msisdn': '27123456789',
            'message': 'yebo',
        })
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(SentSMS.objects.count(), 1)
    
    def test_batch_sms_sending(self):
        self.assertEquals(SentSMS.objects.count(), 0)
        resp = self.client.post(reverse('api:techsys:sms-send'), {
            'to_msisdn': ['27123456780','27123456781','27123456782'],
            'from_msisdn': '27123456789',
            'message': 'yebo'
        })
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(SentSMS.objects.count(), 3)
    
    def test_template_sms_sending(self):
        # not implemented
        resp = self.client.post(reverse('api:techsys:sms-template-send'))
        self.assertEquals(resp.status_code, 405)
    
    def test_send_sms_response(self):
        """
        We get the following back from E-scape when we send them an SMS, make
        sure we can parse it correctly"""
        
        good_response = """PS Bind: Message queued successfully"""
        bad_response = """Anything else really"""
        e = E_Scape("url", "bind")
        response = e.parse_response(good_response)
        self.assertRaises(Exception, e.parse_response, bad_response)
    
    def test_sms_receiving(self):
        # not implemented
        resp = self.client.post(reverse('api:techsys:sms-receive'))
        self.assertEquals(resp.status_code, 405)
Exemplo n.º 5
0
 def setUp(self):
     self.client = APIClient()
     self.client.login(username='******', password='******')
     # create the user we need to be authorized
     self.user = User.objects.get(username='******')
     # load the yaml data
     fp = open('src/vumi/webapp/api/test_data/devquiz.yaml', 'r')
     self.yaml_conversation = ''.join(fp.readlines())
Exemplo n.º 6
0
Arquivo: api.py Projeto: dmaclay/vumi
 def setUp(self):
     self.client = APIClient()
     self.client.login(username='******', password='******')
     # get the user
     self.user = User.objects.get(username='******')
     # make sure the transport's set
     profile = self.user.get_profile()
     profile.transport = Transport.objects.create(name='Clickatell')
     profile.save()
Exemplo n.º 7
0
Arquivo: api.py Projeto: dmaclay/vumi
 def setUp(self):
     self.client = APIClient()
     self.client.login(username='******', password='******')
     # create the user we need to be authorized
     self.user = User.objects.get(username='******')
     # load the yaml data
     fp = open(os.path.join(settings.APP_ROOT, 'webapp', 'api',
                            'test_data', 'devquiz.yaml'), 'r')
     self.yaml_conversation = ''.join(fp.readlines())
Exemplo n.º 8
0
class ClickatellSMSHandlerTestCase(TestCase):

    fixtures = ['user_set']

    def setUp(self):
        self.client = APIClient()
        self.client.login(username='******', password='******')
        # create the user we need to be authorized
        self.user = User.objects.get(username='******')

    def test_sms_receipts(self):
        """
        Receipts received from clickatell should update the status
        """
        [sms] = mock_sent_messages(self.user, count=1,
                                    transport_name='Clickatell',
                                    transport_msg_id='a' * 32)
        self.assertEquals(sms.transport_status, '')
        resp = self.client.post(reverse('api:clickatell:sms-receipt'), {
            'apiMsgId': 'a' * 32,
            'cliMsgId': sms.pk,
            'status': 8,  # OK
            'to': '27123456789',
            'from': '27123456789',
            'timestamp': int(time()),
            'charge': 0.3
        })
        self.assertEquals(resp.status_code, 201)
        sms = SentSMS.objects.get(pk=sms.pk)  # reload
        self.assertEquals(sms.transport_status, '8')

    def test_sms_receiving(self):
        self.assertEquals(ReceivedSMS.objects.count(), 0)
        resp = self.client.post(reverse('api:clickatell:sms-receive'), {
            'to': '27123456789',
            'from': '27123456789',
            'moMsgId': 'a' * 12,
            'api_id': 'b' * 12,
            'text': 'hello world',
            # MySQL format
            'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        })
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(ReceivedSMS.objects.count(), 1)
Exemplo n.º 9
0
 def setUp(self):
     self.client = APIClient()
     self.client.login("api", "password")
     self.user = User.objects.get(username="******")
Exemplo n.º 10
0
 def setUp(self):
     self.client = APIClient()
     self.client.login(username="******", password="******")
     # create the user we need to be authorized
     self.user = User.objects.get(username="******")
Exemplo n.º 11
0
class OperaSMSHandlerTestCase(TestCase):

    fixtures = ["user_set"]

    def setUp(self):
        self.client = APIClient()
        self.client.login(username="******", password="******")
        # create the user we need to be authorized
        self.user = User.objects.get(username="******")

    def test_sms_receipts(self):
        """
        Receipts received from opera should update the status
        """
        [sms] = mock_sent_messages(self.user, count=1, transport_name="Opera", transport_msg_id="001efc31")
        self.assertEquals(sms.transport_status, "")

        raw_xml_post = """
        <?xml version="1.0"?>
        <!DOCTYPE receipts>
        <receipts>
          <receipt>
            <msgid>26567958</msgid>
            <reference>001efc31</reference>
            <msisdn>+27123456789</msisdn>
            <status>D</status>
            <timestamp>20080831T15:59:24</timestamp>
            <billed>NO</billed>
          </receipt>
        </receipts>
        """

        resp = self.client.post(reverse("api:opera:sms-receipt"), raw_xml_post.strip(), content_type="text/xml")
        sms = SentSMS.objects.get(pk=sms.pk)  # reload
        self.assertEquals(sms.transport_status, "D")
        self.assertEquals(resp.status_code, 201)

    def test_sms_sending(self):
        self.assertEquals(SentSMS.objects.count(), 0)
        resp = self.client.post(
            reverse("api:opera:sms-send"), {"to_msisdn": "27123456789", "from_msisdn": "27123456789", "message": "yebo"}
        )
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(SentSMS.objects.count(), 1)

    def test_batch_sms_sending(self):
        self.assertEquals(SentSMS.objects.count(), 0)
        resp = self.client.post(
            reverse("api:opera:sms-send"),
            {
                "to_msisdn": ["27123456780", "27123456781", "27123456782"],
                "from_msisdn": "27123456789",
                "message": "yebo",
            },
        )
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(SentSMS.objects.count(), 3)

    def test_template_sms_sending(self):
        self.assertEquals(SentSMS.objects.count(), 0)
        resp = self.client.post(
            reverse("api:opera:sms-template-send"),
            {
                "to_msisdn": ["27123456780", "27123456781", "27123456782"],
                "template_first_name": ["Name 1", "Name 2", "Name 3"],
                "template_last_name": ["Surname 1", "Surname 2", "Surname 3"],
                "from_msisdn": "27123456789",
                "template": "Hi {{first_name}} {{last_name}}",
            },
        )
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(SentSMS.objects.count(), 3)

    def test_sms_receiving_with_text_plain_headers(self):
        """
        By eavesdropping we got the following log, this is what opera sends.
        DTD is available at https://dragon.sa.operatelecom.com/MEnable/Client/Extra/bspostevent-1_0_0.dtd
        
        
        POST /api/v1/sms/opera/receive.xml HTTP/1.1
        Content-Length: 1798
        Content-Type: text/plain; charset=utf-8
        Authorization: ...
        Host: ....
        """
        receive_sms_doc = """
        <?xml version="1.0"?>
        <!DOCTYPE bspostevent>
        <bspostevent>
          <field name="MOReference" type = "string">282341913</field>
          <field name="IsReceipt" type = "string">NO</field>
          <field name="RemoteNetwork" type = "string">mtn-za</field>
          <field name="BSDate-tomorrow" type = "string">20100605</field>
          <field name="BSDate-today" type = "string">20100604</field>
          <field name="ReceiveDate" type = "date">2010-06-04 15:51:25 +0000</field>
          <field name="Local" type = "string">*32323</field>
          <field name="ClientID" type = "string">4</field>
          <field name="ChannelID" type = "string">111</field>
          <field name="MessageID" type = "string">373736741</field>
          <field name="ReceiptStatus" type = "string"></field>
          <field name="Prefix" type = "string"></field>
          <field name="ClientName" type = "string">Praekelt</field>
          <field name="MobileDevice" type = "string"></field>
          <field name="BSDate-yesterday" type = "string">20100603</field>
          <field name="Remote" type = "string">+27831234567</field>
          <field name="State" type = "string">5</field>
          <field name="MobileNetwork" type = "string">mtn-za</field>
          <field name="MobileNumber" type = "string">+27831234567</field>
          <field name="Text" type = "string">Hello World</field>
          <field name="ServiceID" type = "string">20222</field>
          <field name="RegType" type = "string">1</field>
          <field name="NewSubscriber" type = "string">NO</field>
          <field name="Subscriber" type = "string">+27831234567</field>
          <field name="Parsed" type = "string"></field>
          <field name="ServiceName" type = "string">Prktl Vumi</field>
          <field name="BSDate-thisweek" type = "string">20100531</field>
          <field name="ServiceEndDate" type = "string">2010-06-30 07:47:00 +0200</field>
          <field name="Now" type = "date">2010-06-04 15:51:27 +0000</field>
        </bspostevent>
        """

        self.assertEquals(ReceivedSMS.objects.count(), 0)
        resp = self.client.post(
            reverse("api:opera:sms-receive"), receive_sms_doc.strip(), content_type="text/plain; charset=utf-8"
        )
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(ReceivedSMS.objects.count(), 1)
        sms = ReceivedSMS.objects.latest()
        self.assertEquals(sms.received_at.strftime("%Y-%m-%d %H:%M:%S +0000"), "2010-06-04 15:51:25 +0000")
        self.assertEquals(sms.from_msisdn, "+27831234567")
        self.assertEquals(sms.to_msisdn, "*32323")
        self.assertEquals(sms.transport_name, "Opera")
Exemplo n.º 12
0
Arquivo: api.py Projeto: dmaclay/vumi
 def setUp(self):
     self.client = APIClient()
     self.client.login('api', 'password')
     self.user = User.objects.get(username='******')
Exemplo n.º 13
0
Arquivo: api.py Projeto: dmaclay/vumi
class URLCallbackHandlerTestCase(TestCase):

    fixtures = ['user_set']

    def setUp(self):
        self.client = APIClient()
        self.client.login(username='******', password='******')
        # create the user we need to be authorized
        self.user = User.objects.get(username='******')

    def tearDown(self):
        pass

    def test_setting_callback_url(self):
        self.assertEquals(URLCallback.objects.count(), 0)
        resp = self.client.post(reverse('api:url-callbacks-list'), {
            'name': 'sms_receipt',
            'url': 'http://localhost/url/sms/receipt',
        })
        resp = self.client.post(reverse('api:url-callbacks-list'), {
            'name': 'sms_received',
            'url': 'http://localhost/url/sms/received',
        })
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(URLCallback.objects.count(), 2)
        resp = self.client.post(reverse('api:clickatell:sms-receive'), {
            'to': '27123456789',
            'from': '27123456789',
            'moMsgId': 'a' * 12,
            'api_id': 'b' * 12,
            'text': 'hello world',
            # MySQL format:
            'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        })
        # this should show up in the testing log because pycurl can't
        # connect to the given host for the callback

    def test_setting_multiple_callback_urls(self):
        self.assertEquals(URLCallback.objects.count(), 0)
        for name, urls in [
            ('sms_received', [
                'http://localhost/url/sms/received/1',
                'http://localhost/url/sms/received/2',
            ]),
            ('sms_receipt', [
                'http://localhost/url/sms/receipt/1',
                'http://localhost/url/sms/receipt/2',
            ])]:
            for url in urls:
                resp = self.client.post(reverse('api:url-callbacks-list'), {
                    'name': name,
                    'url': url,
                })
                self.assertEquals(resp.status_code, 200)

        self.assertEquals(URLCallback.objects.count(), 4)
        resp = self.client.post(reverse('api:clickatell:sms-receive'), {
            'to': '27123456789',
            'from': '27123456789',
            'moMsgId': 'a' * 12,
            'api_id': 'b' * 12,
            'text': 'hello world',
            # MySQL format
            'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        })

    def test_updating_callback_urls(self):
        self.assertEquals(URLCallback.objects.count(), 0)
        resp = self.client.post(reverse('api:url-callbacks-list'), {
            'name': 'sms_receipt',
            'url': 'http://localhost/url/sms/receipt',
        })
        self.assertEquals(URLCallback.objects.count(), 1)
        data = json.loads(resp.content)
        resp = self.client.put(reverse('api:url-callback', kwargs={
                'callback_id': data['id'],
            }), {
            'url': 'http://localhost/url/sms/receipt1'
        })
        updated_callback = URLCallback.objects.latest('updated_at')
        self.assertEquals(updated_callback.url,
                          'http://localhost/url/sms/receipt1')

    def test_deleting_callback_urls(self):
        self.assertEquals(URLCallback.objects.count(), 0)
        resp = self.client.post(reverse('api:url-callbacks-list'), {
            'name': 'sms_receipt',
            'url': 'http://localhost/url/sms/receipt',
        })
        data = json.loads(resp.content)
        self.assertEquals(URLCallback.objects.count(), 1)
        resp = self.client.delete(reverse('api:url-callback', kwargs={
            'callback_id': data['id'],
        }))
        self.assertEquals(resp.status_code, 204)
        self.assertEquals(resp.content, '')
        self.assertEquals(URLCallback.objects.count(), 0)
Exemplo n.º 14
0
class E_ScapeSMSHandlerTestCase(TestCase):
    
    fixtures = ['user_set']
    
    def setUp(self):
        self.client = APIClient()
        self.client.login(username='******', password='******')
        # create the user we need to be authorized
        self.user = User.objects.get(username='******')
    
    def test_sms_receipts(self):
        """
        E-Scape currently doesn't send us sms receipts, shouldn't respond
        """
        resp = self.client.post(reverse('api:e-scape:sms-receipt'))
        self.assertEquals(resp.status_code, 405)
        resp = self.client.get(reverse('api:e-scape:sms-receipt'))
        self.assertEquals(resp.status_code, 405)
    
    def test_sms_sending(self):
        self.assertEquals(SentSMS.objects.count(), 0)
        resp = self.client.post(reverse('api:e-scape:sms-send'), {
            'to_msisdn': '27123456789',
            'from_msisdn': '27123456789',
            'message': 'yebo',
        })
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(SentSMS.objects.count(), 1)
    
    def test_batch_sms_sending(self):
        self.assertEquals(SentSMS.objects.count(), 0)
        resp = self.client.post(reverse('api:e-scape:sms-send'), {
            'to_msisdn': ['27123456780','27123456781','27123456782'],
            'from_msisdn': '27123456789',
            'message': 'yebo'
        })
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(SentSMS.objects.count(), 3)
    
    def test_template_sms_sending(self):
        self.assertEquals(SentSMS.objects.count(), 0)
        resp = self.client.post(reverse('api:e-scape:sms-template-send'), {
            'to_msisdn': ['27123456780','27123456781','27123456782'],
            'template_first_name': ['Name 1', 'Name 2', 'Name 3'],
            'template_last_name': ['Surname 1', 'Surname 2', 'Surname 3'],
            'from_msisdn': '27123456789',
            'template': 'Hi {{first_name}} {{last_name}}',
        })
        self.assertEquals(resp.status_code, 200)
        self.assertEquals(SentSMS.objects.count(), 3)
    
    def test_send_sms_response(self):
        """
        We get the following back from E-scape when we send them an SMS, make
        sure we can parse it correctly"""
        
        html = """
        <table class="widefat" border="0">
            <thead>
                <tr>
                    <th>from</th>
                    <th>to</th>
                    <th>smsc</th>
                    <th>status</th>
                    <th>text</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>+35566</td>
                    <td>+44778962937</td>
                    <td>ESC-P1Celtel</td>
                    <td>0: Accepted for delivery</td>
                    <td> http://www.mobi-fee.com/link/g.lnk?ID=135</td>
                </tr>
            </tbody>
            <tfoot>
                <tr>
                    <th>from</th>
                    <th>to</th>
                    <th>smsc</th>
                    <th>status</th>
                    <th>text</th>
                </tr>
            </tfoot>
        </table>
        """
        e = E_Scape('api_id')
        [response] = e.parse_response(html)
        self.assertEquals(response.sender, '+35566')
        self.assertEquals(response.recipient, '+44778962937')
        self.assertEquals(response.smsc, 'ESC-P1Celtel')
        self.assertEquals(response.status, ['0', 'Accepted for delivery'])
        self.assertEquals(response.text, ' http://www.mobi-fee.com/link/g.lnk?ID=135')
    
    def test_sms_receiving(self):
        self.assertEquals(ReceivedSMS.objects.count(), 0)
        resp = self.client.get(reverse('api:e-scape:sms-receive'), {
            'smsc': 'id of sms center',
            'svc': 'name of the service',
            's': 'originator',
            'r': 'recipient',
            'text': 'actual message'
        })
        self.assertEquals(resp.status_code, 200)
        # make sure we don't send any headers or content. If we do we'll 
        # automatically send a reply, currently that's not the 
        # desired behaviour.
        self.assertEquals(resp.get('X-Kannel-From', None), None)
        self.assertEquals(resp.get('X-Kannel-To', None), None)
        self.assertEquals(resp.get('X-Kannel-SMSC', None), None)
        self.assertEquals(resp.get('X-Kannel-Service', None), None)
        self.assertEquals(resp.content, '')
        
        self.assertEquals(ReceivedSMS.objects.count(), 1)
        sms = ReceivedSMS.objects.latest()
        import time
        # grmbl messy datetime comparisons
        self.assertAlmostEqual(
            time.mktime(sms.received_at.utctimetuple()),
            time.mktime(datetime.utcnow().utctimetuple()),
            places=1
        )
        self.assertEquals(sms.from_msisdn, 'originator')
        self.assertEquals(sms.to_msisdn, 'recipient')
        self.assertEquals(sms.message, 'actual message')
        self.assertEquals(sms.transport_name, 'E-scape')