1
# friends-service -- send & receive messages from any social network
2
# Copyright (C) 2012 Canonical Ltd
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.
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.
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/>.
16
"""Test the Flickr plugin."""
25
from gi.repository import Dee
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
35
from unittest import mock
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)
46
@mock.patch('friends.utils.download._soup', mock.Mock())
47
class TestFlickr(unittest.TestCase):
48
"""Test the Flickr API."""
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')
59
# Stop log mocking, and return sub-thread operation to asynchronous.
61
Base._SYNCHRONIZE = False
65
def test_features(self):
66
# The set of public features.
67
self.assertEqual(Flickr.get_features(), ['receive'])
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):
78
friends.errors.AuthorizationError:\
79
No Flickr user id available (account: faker/than fake)
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
91
self.protocol('receive')
93
self.assertEqual(self.log_mock.empty(), '')
95
self.assertEqual(TestModel.get_n_rows(), 0)
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
103
# Sorry, the login is unsuccessful, even though it adds a user_id
104
# key to the account.
105
self.account.user_id = 'bart'
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):
114
friends.errors.AuthorizationError:\
115
No Flickr user id available (account: faker/than fake)
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
125
# Perform a successful login.
126
self.account.user_id = 'cate'
128
with mock.patch.object(self.protocol, '_login',
129
side_effect=side_effect):
130
self.protocol('receive')
132
self.assertEqual(self.log_mock.empty(), '')
133
# But also no photos.
134
self.assertEqual(TestModel.get_n_rows(), 0)
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',
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):
154
friends.errors.AuthorizationError:\
155
No Flickr user id available (account: faker/than fake)
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.
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):
173
friends.errors.AuthorizationError:\
174
No Flickr user id available (account: faker/than fake)
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',
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')
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',
212
api_key='36f660117e6555a9cbda4309cfaf72d0',
213
method='flickr.photos.getContactsPublicPhotos',
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)
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.
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))
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')
264
'http://farmanimalz.static.flickr.com/1/789_ghi_b.jpg')
267
'http://farmanimalz.static.flickr.com/1/789_ghi_m.jpg')
270
'http://farmanimalz.static.flickr.com/1/789_ghi_t.jpg')
271
self.assertEqual(col('sender'), '789')
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')