e2254eaee4bcbe5c25e93bfc24adce7cfe76f930
[pixelated-user-agent.git] / service / test / unit / config / test_sessions.py
1 # -*- encoding:utf-8 -*-
2 #
3 # Copyright (c) 2014 ThoughtWorks, Inc.
4 #
5 # Pixelated is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Pixelated is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU Affero General Public License for more details.
14 #
15 # You should have received a copy of the GNU Affero General Public License
16 # along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
17
18 from mock import patch
19 from mock import MagicMock
20 from mockito import when
21 from twisted.internet import defer
22 from pixelated.config.sessions import LeapSession, SessionCache, LeapSessionFactory, SoledadWrongPassphraseException
23 from pixelated.bitmask_libraries.keymanager import UploadKeyError
24 from test.unit.bitmask_libraries.test_abstract_leap import AbstractLeapTest
25 from leap.common.events.catalog import KEYMANAGER_FINISHED_KEY_GENERATION
26 from leap.soledad.common.crypto import WrongMacError, UnknownMacMethodError
27
28
29 class SessionTest(AbstractLeapTest):
30
31     def setUp(self):
32         super(SessionTest, self).setUp()
33         self.smtp_mock = MagicMock()
34
35     @patch('pixelated.config.sessions.register')
36     @patch('pixelated.config.sessions.Account')
37     @defer.inlineCallbacks
38     def test_background_jobs_are_started_during_initial_sync(self, *unused):
39         mail_fetcher_mock = MagicMock()
40         with patch('pixelated.config.sessions.reactor.callFromThread', new=_execute_func) as _:
41             with patch.object(LeapSession, '_create_incoming_mail_fetcher', return_value=mail_fetcher_mock) as _:
42                 session = self._create_session()
43                 yield session.first_required_sync()
44                 mail_fetcher_mock.startService.assert_called_once()
45
46     @patch('pixelated.config.sessions.register')
47     @defer.inlineCallbacks
48     def test_upload_key_error_closes_the_session(self, _):
49         when(self.keymanager).generate_openpgp_key().thenRaise(UploadKeyError('Could not upload key'))
50         session = self._create_session()
51         session.close = MagicMock()
52
53         with self.assertRaises(UploadKeyError):
54             yield session.finish_bootstrap()
55             session.close.assert_called_once()
56
57     @patch('pixelated.config.sessions.register')
58     @patch('pixelated.config.sessions.unregister')
59     @patch('pixelated.config.sessions.Account')
60     @defer.inlineCallbacks
61     def test_that_close_stops_background_jobs(self, *unused):
62         mail_fetcher_mock = MagicMock()
63         with patch('pixelated.config.sessions.reactor.callFromThread', new=_execute_func) as _:
64             with patch.object(LeapSession, '_create_incoming_mail_fetcher', return_value=mail_fetcher_mock) as _:
65                 session = self._create_session()
66                 yield session.first_required_sync()
67                 session.close()
68                 mail_fetcher_mock.stopService.assert_called_once()
69
70     @patch('pixelated.config.sessions.register')
71     @defer.inlineCallbacks
72     def test_that_sync_defers_to_soledad(self, *unused):
73         session = self._create_session()
74         yield session.sync()
75         self.soledad_session.sync.assert_called_once()
76
77     def test_session_registers_to_generated_keys(self):
78         email = 'someone@somedomain.tld'
79         self.provider.address_for.return_value = email
80         with patch('pixelated.config.sessions.register') as register_mock:
81             session = self._create_session()
82
83             register_mock.assert_called_once_with(KEYMANAGER_FINISHED_KEY_GENERATION, session._set_fresh_account, uid=email)
84
85     @patch('pixelated.config.sessions.register')
86     def test_close_unregisters_from_generate_keys_events(self, _):
87         email = 'someone@somedomain.tld'
88         self.provider.address_for.return_value = email
89         session = self._create_session()
90
91         with patch('pixelated.config.sessions.unregister') as unregister_mock:
92             session.close()
93
94             unregister_mock.assert_called_once_with(KEYMANAGER_FINISHED_KEY_GENERATION, uid=email)
95
96     @patch('pixelated.config.sessions.register')
97     def test_close_stops_soledad(self, _):
98         email = 'someone@somedomain.tld'
99         self.provider.address_for.return_value = email
100         session = self._create_session()
101
102         with patch('pixelated.config.sessions.unregister') as unregister_mock:
103             session.close()
104
105         self.soledad_session.close.assert_called_once_with()
106
107     @patch('pixelated.config.sessions.register')
108     def test_close_removes_session_from_cache(self, _):
109         email = 'someone@somedomain.tld'
110         self.provider.address_for.return_value = email
111         session = self._create_session()
112
113         key = SessionCache.session_key(self.provider, self.auth.username)
114         SessionCache.remember_session(key, session)
115
116         self.assertEqual(session, SessionCache.lookup_session(key))
117
118         with patch('pixelated.config.sessions.unregister') as unregister_mock:
119             session.close()
120
121         self.assertIsNone(SessionCache.lookup_session(key))
122
123     @patch('pixelated.config.sessions.register')
124     def test_close_ends_account_session(self, _):
125         account_mock = MagicMock()
126         email = 'someone@somedomain.tld'
127         self.provider.address_for.return_value = email
128         session = self._create_session()
129         session.account = account_mock
130
131         with patch('pixelated.config.sessions.unregister') as unregister_mock:
132             session.close()
133
134         account_mock.end_session.assert_called_once_with()
135
136     @patch('pixelated.config.sessions.register')
137     def test_session_fresh_is_initially_false(self, _):
138         session = self._create_session()
139
140         self.assertFalse(session.fresh_account)
141
142     @patch('pixelated.config.sessions.register')
143     def test_session_sets_status_to_fresh_on_key_generation_event(self, _):
144         session = self._create_session()
145         self.provider.address_for.return_value = 'someone@somedomain.tld'
146
147         session._set_fresh_account(None, 'someone@somedomain.tld')
148
149         self.assertTrue(session.fresh_account)
150
151     @patch('pixelated.config.sessions.register')
152     def test_closed_session_not_reused(self, _):
153         session = self._create_session()
154         SessionCache.remember_session('somekey', session)
155         session._is_closed = True
156
157         result = SessionCache.lookup_session('somekey')
158
159         self.assertIsNone(result)
160
161     @patch('pixelated.config.sessions.register')
162     def test_session_does_not_set_status_fresh_for_unkown_emails(self, _):
163         session = self._create_session()
164         self.provider.address_for.return_value = 'someone@somedomain.tld'
165
166         session._set_fresh_account(None, 'another_email@somedomain.tld')
167
168         self.assertFalse(session.fresh_account)
169
170     def test_session_setup_soledad_with_utf8_characters(self):
171         api_cert = MagicMock()
172         leap_session_factory = LeapSessionFactory(self.provider)
173
174         with patch('pixelated.config.sessions.threads.deferToThread') as deferToThreadMock:
175             leap_session_factory.setup_soledad('self.token', u'self.uuid', 'Kl√ľnter', api_cert)
176             deferToThreadMock.assert_called_once()
177             args, kwargs = deferToThreadMock.call_args
178             uuid_arg = args[1]
179             pass_arg = kwargs['passphrase']
180             self.assertIs(type(uuid_arg), str, "expected uuid argument to be a string")
181             self.assertIs(type(pass_arg), unicode, "expected passphrase argument to be unicode")
182
183     @defer.inlineCallbacks
184     def test_sessions__setup_soledad__will_raise_wrong_passphrase_exception_on_errors(self):
185         leap_session_factory = LeapSessionFactory(self.provider)
186
187         with patch('pixelated.config.sessions.Soledad', side_effect=WrongMacError("oh no")):
188             with self.assertRaises(SoledadWrongPassphraseException):
189                 yield leap_session_factory.setup_soledad('token', u'uuid', 'passphrase', None)
190
191         with patch('pixelated.config.sessions.Soledad', side_effect=UnknownMacMethodError("oh no")):
192             with self.assertRaises(SoledadWrongPassphraseException):
193                 yield leap_session_factory.setup_soledad('token', u'uuid', 'passphrase', None)
194
195     def _create_session(self):
196         return LeapSession(self.provider, self.auth, self.mail_store, self.soledad_session, self.keymanager, self.smtp_mock)
197
198
199 def _execute_func(func):
200     func()