~robru/friends/early-dbus-interface

« back to all changes in this revision

Viewing changes to friends/tests/test_flickr.py

  • Committer: Ken VanDine
  • Date: 2012-10-13 01:27:15 UTC
  • Revision ID: ken.vandine@canonical.com-20121013012715-gxfoi1oo30wdm8dv
initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# friends-service -- send & receive messages from any social network
 
2
# Copyright (C) 2012  Canonical Ltd
 
3
#
 
4
# This program is free software: you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation, version 3 of the License.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 
 
16
"""Test the Flickr plugin."""
 
17
 
 
18
__all__ = [
 
19
    'TestFlickr',
 
20
    ]
 
21
 
 
22
 
 
23
import unittest
 
24
 
 
25
from gi.repository import Dee
 
26
 
 
27
from friends.protocols.flickr import Flickr
 
28
from friends.testing.helpers import FakeAccount
 
29
from friends.testing.mocks import FakeSoupMessage, LogMock
 
30
from friends.utils.base import Base
 
31
from friends.utils.model import COLUMN_INDICES, COLUMN_TYPES
 
32
 
 
33
try:
 
34
    # Python 3.3
 
35
    from unittest import mock
 
36
except ImportError:
 
37
    import mock
 
38
 
 
39
 
 
40
# Create a test model that will not interfere with the user's environment.
 
41
# We'll use this object as a mock of the real model.
 
42
TestModel = Dee.SharedModel.new('com.canonical.Friends.TestSharedModel')
 
43
TestModel.set_schema_full(COLUMN_TYPES)
 
44
 
 
45
 
 
46
@mock.patch('friends.utils.download._soup', mock.Mock())
 
47
class TestFlickr(unittest.TestCase):
 
48
    """Test the Flickr API."""
 
49
 
 
50
    def setUp(self):
 
51
        self.account = FakeAccount()
 
52
        self.protocol = Flickr(self.account)
 
53
        # Enable sub-thread synchronization, and mock out the loggers.
 
54
        Base._SYNCHRONIZE = True
 
55
        self.log_mock = LogMock('friends.utils.base',
 
56
                                'friends.protocols.flickr')
 
57
 
 
58
    def tearDown(self):
 
59
        # Stop log mocking, and return sub-thread operation to asynchronous.
 
60
        self.log_mock.stop()
 
61
        Base._SYNCHRONIZE = False
 
62
        # Reset the database.
 
63
        TestModel.clear()
 
64
 
 
65
    def test_features(self):
 
66
        # The set of public features.
 
67
        self.assertEqual(Flickr.get_features(), ['receive'])
 
68
 
 
69
    def test_failed_login(self):
 
70
        # Force the Flickr login to fail.
 
71
        with mock.patch.object(self.protocol, '_get_nsid', return_value=None):
 
72
            self.protocol('receive')
 
73
        self.assertEqual(self.log_mock.empty(), """\
 
74
Flickr: No NSID available
 
75
Friends operation exception:
 
76
 Traceback (most recent call last):
 
77
 ...
 
78
friends.errors.AuthorizationError:\
 
79
 No Flickr user id available (account: faker/than fake)
 
80
""")
 
81
 
 
82
    @mock.patch('friends.utils.download.Soup.Message',
 
83
                FakeSoupMessage('friends.tests.data', 'flickr-nophotos.dat'))
 
84
    @mock.patch('friends.utils.base.Model', TestModel)
 
85
    def test_already_logged_in(self):
 
86
        # Try to get the data when already logged in.
 
87
        self.account.user_id = 'anne'
 
88
        # There's no data, and no way to test that the user_nsid was actually
 
89
        # used, except for the side effect of not getting an
 
90
        # AuthorizationError.
 
91
        self.protocol('receive')
 
92
        # No error messages.
 
93
        self.assertEqual(self.log_mock.empty(), '')
 
94
        # But also no photos.
 
95
        self.assertEqual(TestModel.get_n_rows(), 0)
 
96
 
 
97
    @mock.patch('friends.utils.download.Soup.Message',
 
98
                FakeSoupMessage('friends.tests.data', 'flickr-nophotos.dat'))
 
99
    def test_unsuccessful_login(self):
 
100
        # The user is not already logged in, but the act of logging in
 
101
        # fails.
 
102
        def side_effect():
 
103
            # Sorry, the login is unsuccessful, even though it adds a user_id
 
104
            # key to the account.
 
105
            self.account.user_id = 'bart'
 
106
            return False
 
107
        with mock.patch.object(self.protocol, '_login',
 
108
                               side_effect=side_effect):
 
109
            self.protocol('receive')
 
110
        self.assertEqual(self.log_mock.empty(), """\
 
111
Friends operation exception:
 
112
 Traceback (most recent call last):
 
113
 ...
 
114
friends.errors.AuthorizationError:\
 
115
 No Flickr user id available (account: faker/than fake)
 
116
""")
 
117
 
 
118
    @mock.patch('friends.utils.download.Soup.Message',
 
119
                FakeSoupMessage('friends.tests.data', 'flickr-nophotos.dat'))
 
120
    @mock.patch('friends.utils.base.Model', TestModel)
 
121
    def test_successful_login(self):
 
122
        # The user is not already logged in, but the act of logging in
 
123
        # succeeds.
 
124
        def side_effect():
 
125
            # Perform a successful login.
 
126
            self.account.user_id = 'cate'
 
127
            return True
 
128
        with mock.patch.object(self.protocol, '_login',
 
129
                               side_effect=side_effect):
 
130
            self.protocol('receive')
 
131
        # No error message.
 
132
        self.assertEqual(self.log_mock.empty(), '')
 
133
        # But also no photos.
 
134
        self.assertEqual(TestModel.get_n_rows(), 0)
 
135
 
 
136
    @mock.patch('friends.utils.download.Soup.Message',
 
137
                FakeSoupMessage('friends.tests.data', 'flickr-nophotos.dat'))
 
138
    @mock.patch('friends.utils.authentication.Authentication.login',
 
139
                # No AccessToken, so for all intents-and-purposes; fail!
 
140
                return_value=dict(username='Bob Dobbs',
 
141
                                  user_nsid='bob',
 
142
                                  TokenSecret='abc'))
 
143
    def test_login_unsuccessful_authentication(self, mock):
 
144
        # Logging in required communication with the account service to get an
 
145
        # AccessToken, but this fails.
 
146
        self.protocol('receive')
 
147
        self.assertEqual(self.log_mock.empty(), """\
 
148
No AccessToken in Flickr session:\
 
149
 {'TokenSecret': 'abc', 'username': 'Bob Dobbs', 'user_nsid': 'bob'}
 
150
Flickr: No NSID available
 
151
Friends operation exception:
 
152
 Traceback (most recent call last):
 
153
 ...
 
154
friends.errors.AuthorizationError:\
 
155
 No Flickr user id available (account: faker/than fake)
 
156
""")
 
157
 
 
158
    @mock.patch('friends.utils.download.Soup.Message',
 
159
                FakeSoupMessage('friends.tests.data', 'flickr-nophotos.dat'))
 
160
    @mock.patch('friends.utils.authentication.Authentication.login',
 
161
                # login() callback never happens.
 
162
                return_value=None)
 
163
    def test_login_unsuccessful_authentication_no_callback(self, mock):
 
164
        # Logging in required communication with the account service to get an
 
165
        # AccessToken, but this fails.
 
166
        self.protocol('receive')
 
167
        self.assertEqual(self.log_mock.empty(), """\
 
168
No Flickr authentication results received.
 
169
Flickr: No NSID available
 
170
Friends operation exception:
 
171
 Traceback (most recent call last):
 
172
 ...
 
173
friends.errors.AuthorizationError:\
 
174
 No Flickr user id available (account: faker/than fake)
 
175
""")
 
176
 
 
177
    @mock.patch('friends.utils.download.Soup.Message',
 
178
                FakeSoupMessage('friends.tests.data', 'flickr-nophotos.dat'))
 
179
    @mock.patch('friends.utils.authentication.Authentication.login',
 
180
                return_value=dict(username='Bob Dobbs',
 
181
                                  user_nsid='bob',
 
182
                                  AccessToken='123',
 
183
                                  TokenSecret='abc'))
 
184
    def test_login_successful_authentication(self, mock):
 
185
        # Logging in required communication with the account service to get an
 
186
        # AccessToken, but this fails.
 
187
        self.protocol('receive')
 
188
        # Make sure our account data got properly updated.
 
189
        self.assertEqual(self.account.user_name, 'Bob Dobbs')
 
190
        self.assertEqual(self.account.user_id, 'bob')
 
191
        self.assertEqual(self.account.access_token, '123')
 
192
        self.assertEqual(self.account.secret_token, 'abc')
 
193
 
 
194
    def test_get(self):
 
195
        # Make sure that the REST GET url looks right.
 
196
        with mock.patch.object(self.protocol, '_get_nsid', return_value='jim'):
 
197
            with mock.patch('friends.protocols.flickr.get_json',
 
198
                            return_value={}) as cm:
 
199
                self.protocol('receive')
 
200
        # Unpack the arguments that the mock was called with and test that the
 
201
        # arguments, especially to the GET are what we expected.
 
202
        all_call_args = cm.call_args_list
 
203
        # GET was called once.
 
204
        self.assertEqual(len(all_call_args), 1)
 
205
        url, GET_args = all_call_args[0][0]
 
206
        self.assertEqual(url, 'http://api.flickr.com/services/rest')
 
207
        self.assertEqual(GET_args, dict(
 
208
            extras='date_updated,owner_name,icon_server',
 
209
            user_id='jim',
 
210
            format='json',
 
211
            nojsoncallback='1',
 
212
            api_key='36f660117e6555a9cbda4309cfaf72d0',
 
213
            method='flickr.photos.getContactsPublicPhotos',
 
214
            ))
 
215
 
 
216
    @mock.patch('friends.utils.download.Soup.Message',
 
217
                FakeSoupMessage('friends.tests.data', 'flickr-nophotos.dat'))
 
218
    @mock.patch('friends.utils.base.Model', TestModel)
 
219
    def test_no_photos(self):
 
220
        # The JSON data in response to the GET request returned no photos.
 
221
        with mock.patch.object(self.protocol, '_get_nsid', return_value='jim'):
 
222
            # No photos are returned in the JSON data.
 
223
            self.protocol('receive')
 
224
        self.assertEqual(TestModel.get_n_rows(), 0)
 
225
 
 
226
    @mock.patch('friends.utils.download.Soup.Message',
 
227
                FakeSoupMessage('friends.tests.data', 'flickr-full.dat'))
 
228
    @mock.patch('friends.utils.base.Model', TestModel)
 
229
    def test_flickr_data(self):
 
230
        # Test the undocumented and apparently crufty reformatting of the raw
 
231
        # JSON Flickr data into the format expected internally.
 
232
        #
 
233
        # Start by setting up a fake account id.
 
234
        self.account.id = 'lerxst'
 
235
        with mock.patch.object(self.protocol, '_get_nsid', return_value='jim'):
 
236
            self.protocol('receive')
 
237
        self.assertEqual(TestModel.get_n_rows(), 3)
 
238
        # Image 1 data in the first row.
 
239
        row = list(TestModel.get_row(0))
 
240
        # For convenience.
 
241
        def col(name):
 
242
            return row[COLUMN_INDICES[name]]
 
243
        self.assertEqual(col('message'), 'ant')
 
244
        self.assertEqual(col('html'), 'ant')
 
245
        self.assertEqual(col('message_ids'), [['flickr', 'lerxst', '801']])
 
246
        self.assertEqual(col('sender'), '123')
 
247
        self.assertEqual(col('timestamp'), '2012-05-10T13:36:45')
 
248
        self.assertFalse(col('from_me'))
 
249
        row = list(TestModel.get_row(1))
 
250
        # Image 2 data.  The image is from the account owner.
 
251
        self.assertEqual(col('message'), 'bee')
 
252
        self.assertEqual(col('html'), 'bee')
 
253
        self.assertEqual(col('message_ids'), [['flickr', 'lerxst', '802']])
 
254
        self.assertEqual(col('sender'), '456')
 
255
        self.assertEqual(col('sender_nick'), 'Alex Lifeson')
 
256
        self.assertTrue(col('from_me'))
 
257
        # Image 3 data.  This data set has some additional entries that allow
 
258
        # various image urls and other keys to be added.
 
259
        row = list(TestModel.get_row(2))
 
260
        self.assertEqual(col('message'), 'cat')
 
261
        self.assertEqual(col('html'), 'cat')
 
262
        self.assertEqual(
 
263
            col('img_url'),
 
264
            'http://farmanimalz.static.flickr.com/1/789_ghi_b.jpg')
 
265
        self.assertEqual(
 
266
            col('img_src'),
 
267
            'http://farmanimalz.static.flickr.com/1/789_ghi_m.jpg')
 
268
        self.assertEqual(
 
269
            col('img_thumb'),
 
270
            'http://farmanimalz.static.flickr.com/1/789_ghi_t.jpg')
 
271
        self.assertEqual(col('sender'), '789')
 
272
        self.assertEqual(
 
273
            col('icon_uri'),
 
274
            'http://farmiconz.static.flickr.com/9/buddyicons/789.jpg')
 
275
        self.assertFalse(col('from_me'))
 
276
        self.assertEqual(col('sender'), '789')
 
277
        self.assertEqual(col('sender_nick'), 'Bob Dobbs')
 
278
        self.assertEqual(col('url'), 'http://www.flickr.com/people/789')