# coding=utf-8 """Unit tests for salmon.py. TODO: test error handling """ from __future__ import unicode_literals import copy import datetime import urllib from django_salmon import magicsigs import mock from oauth_dropins.webutil.testutil import requests_response, UrlopenResult import requests import common from models import MagicKey, Response from salmon import app import testutil @mock.patch('requests.post') @mock.patch('requests.get') @mock.patch('urllib2.urlopen') class SalmonTest(testutil.TestCase): def setUp(self): super(SalmonTest, self).setUp() self.key = MagicKey.get_or_create('alice') def send_slap(self, mock_urlopen, mock_get, mock_post, atom_slap): # salmon magic key discovery. first host-meta, then webfinger mock_urlopen.side_effect = [ UrlopenResult(200, """\ """), UrlopenResult(200, """\ alice@fedsoc.net """ % self.key.href()), ] # webmention discovery mock_get.return_value = requests_response( '') # webmention post mock_post.return_value = requests_response() slap = magicsigs.magic_envelope(atom_slap, common.CONTENT_TYPE_ATOM, self.key) got = app.get_response('/me@foo.com/salmon', method='POST', body=slap) self.assertEquals(200, got.status_int) # check salmon magic key discovery mock_urlopen.assert_has_calls(( mock.call('http://fedsoc.net/.well-known/host-meta'), mock.call('http://webfinger/alice@fedsoc.net'), )) # check webmention discovery self.expected_headers = copy.deepcopy(common.HEADERS) self.expected_headers['Accept'] = '*/*' mock_get.assert_called_once_with( 'http://orig/post', headers=common.HEADERS, verify=False) def test_reply(self, mock_urlopen, mock_get, mock_post): atom_reply = """\ https://my/reply https://my/reply Alice alice@fedsoc.net http://orig/post I hereby reply. My Reply %s """ % datetime.datetime.now().isoformat(b'T') self.send_slap(mock_urlopen, mock_get, mock_post, atom_reply) # check webmention post mock_post.assert_called_once_with( 'http://orig/webmention', data={'source': 'https://my/reply', 'target': 'http://orig/post'}, allow_redirects=False, headers=self.expected_headers, verify=False) # check stored response resp = Response.get_by_id('https://my/reply http://orig/post') self.assertEqual('in', resp.direction) self.assertEqual('ostatus', resp.protocol) self.assertEqual('complete', resp.status) self.assertEqual(atom_reply, resp.source_atom) def test_like(self, mock_urlopen, mock_get, mock_post): atom_like = """\ https://my/like Alice alice@fedsoc.net http://activitystrea.ms/schema/1.0/like http://orig/post %s """ % datetime.datetime.now().isoformat(b'T') self.send_slap(mock_urlopen, mock_get, mock_post, atom_like) # check webmention post mock_post.assert_called_once_with( 'http://orig/webmention', data={ 'source': 'http://localhost/render?source=https%3A%2F%2Fmy%2Flike&target=http%3A%2F%2Forig%2Fpost', 'target': 'http://orig/post', }, allow_redirects=False, headers=self.expected_headers, verify=False) # check stored response resp = Response.get_by_id('https://my/like http://orig/post') self.assertEqual('in', resp.direction) self.assertEqual('ostatus', resp.protocol) self.assertEqual('complete', resp.status) self.assertEqual(atom_like, resp.source_atom) def test_bad_envelope(self, mock_urlopen, mock_get, mock_post): got = app.get_response('/foo.com/salmon', method='POST', body='not xml'.encode('utf-8')) self.assertEquals(400, got.status_int) def test_bad_inner_xml(self, mock_urlopen, mock_get, mock_post): slap = magicsigs.magic_envelope('not xml', common.CONTENT_TYPE_ATOM, self.key) got = app.get_response('/foo.com/salmon', method='POST', body=slap) self.assertEquals(400, got.status_int) def test_rsvp_not_supported(self, mock_urlopen, mock_get, mock_post): slap = magicsigs.magic_envelope("""\ https://my/rsvp http://activitystrea.ms/schema/1.0/rsvp http://orig/event """, common.CONTENT_TYPE_ATOM, self.key) got = app.get_response('/foo.com/salmon', method='POST', body=slap) self.assertEquals(501, got.status_int)