~nataliabidart/ubuntu/natty/ubuntuone-control-panel/ubuntuone-control-panel-0.9.3

« back to all changes in this revision

Viewing changes to ubuntuone/controlpanel/tests/test_backend.py

Tags: upstream-0.5.1
ImportĀ upstreamĀ versionĀ 0.5.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
from twisted.internet.defer import inlineCallbacks
26
26
from ubuntuone.devtools.handlers import MementoHandler
27
27
 
28
 
from ubuntuone.controlpanel import backend
29
 
from ubuntuone.controlpanel.backend import (ACCOUNT_API,
30
 
    DEVICES_API, DEVICE_REMOVE_API, QUOTA_API,
 
28
from ubuntuone.controlpanel import backend, replication_client
 
29
from ubuntuone.controlpanel.backend import (bool_str,
 
30
    ACCOUNT_API, DEVICES_API, DEVICE_REMOVE_API, QUOTA_API,
31
31
    FILE_SYNC_DISABLED,
32
32
    FILE_SYNC_DISCONNECTED,
33
33
    FILE_SYNC_ERROR,
37
37
    FILE_SYNC_UNKNOWN,
38
38
    MSG_KEY, STATUS_KEY,
39
39
)
40
 
 
41
 
from ubuntuone.controlpanel.tests import TestCase
 
40
from ubuntuone.controlpanel.tests import (TestCase,
 
41
    EXPECTED_ACCOUNT_INFO,
 
42
    EXPECTED_ACCOUNT_INFO_WITH_CURRENT_PLAN,
 
43
    EXPECTED_DEVICES_INFO,
 
44
    SAMPLE_ACCOUNT_NO_CURRENT_PLAN,
 
45
    SAMPLE_ACCOUNT_WITH_CURRENT_PLAN,
 
46
    SAMPLE_DEVICES_JSON,
 
47
    SAMPLE_FOLDERS,
 
48
    SAMPLE_QUOTA_JSON,
 
49
    SAMPLE_SHARED,
 
50
    SAMPLE_SHARES,
 
51
    TOKEN,
 
52
)
42
53
from ubuntuone.controlpanel.webclient import WebClientError
43
54
 
44
 
SAMPLE_CREDENTIALS = {"token": "ABC1234DEF"}
45
 
 
46
 
SAMPLE_ACCOUNT_JSON = """
47
 
{
48
 
    "username": "andrewpz",
49
 
    "openid": "https://login.launchpad.net/+id/abcdefg",
50
 
    "first_name": "Andrew P.",
51
 
    "last_name": "Zoilo",
52
 
    "couchdb": {
53
 
        "host": "https://couchdb.one.ubuntu.com",
54
 
        "root": "https://couchdb.one.ubuntu.com/u/abc/def/12345",
55
 
        "dbpath": "u/abc/def/12345"
56
 
    },
57
 
    "couchdb_root": "https://couchdb.one.ubuntu.com/u/abc/def/12345",
58
 
    "email": "andrewpz@protocultura.net",%s
59
 
    "nickname": "Andrew P. Zoilo",
60
 
    "id": 12345,
61
 
    "subscription": {
62
 
        "upgrade_available": false,
63
 
        "description": "Paid Plan, 50 GB of storage",
64
 
        "trial": false,
65
 
        "started": "2010-03-24T18:38:38Z",
66
 
        "is_paid": true,
67
 
        "expires": null,
68
 
        "qty": 1,
69
 
        "price": 0.0,
70
 
        "currency": null,
71
 
        "id": 654321,
72
 
        "name": "50 GB"
73
 
    }
74
 
}
75
 
"""
76
 
 
77
 
CURRENT_PLAN = "Ubuntu One Basic (2 GB) + 1 x 20-Pack with 20 GB (monthly)"
78
 
SAMPLE_CURRENT_PLAN = '\n    "current_plan": "%s",' % CURRENT_PLAN
79
 
 
80
 
SAMPLE_ACCOUNT_NO_CURRENT_PLAN = SAMPLE_ACCOUNT_JSON % ''
81
 
SAMPLE_ACCOUNT_WITH_CURRENT_PLAN = SAMPLE_ACCOUNT_JSON % SAMPLE_CURRENT_PLAN
82
 
 
83
 
 
84
 
SAMPLE_QUOTA_JSON = """
85
 
{
86
 
    "total": 53687091200,
87
 
    "used": 2350345156
88
 
}
89
 
"""
90
 
 
91
 
EXPECTED_ACCOUNT_INFO = {
92
 
    "quota_used": "2350345156",
93
 
    "quota_total": "53687091200",
94
 
    "type": "Paid Plan, 50 GB of storage",
95
 
    "name": "Andrew P. Zoilo",
96
 
    "email": "andrewpz@protocultura.net",
97
 
}
98
 
 
99
 
EXPECTED_ACCOUNT_INFO_WITH_CURRENT_PLAN = {
100
 
    "quota_used": "2350345156",
101
 
    "quota_total": "53687091200",
102
 
    "type": CURRENT_PLAN,
103
 
    "name": "Andrew P. Zoilo",
104
 
    "email": "andrewpz@protocultura.net",
105
 
}
106
 
 
107
 
SAMPLE_DEVICES_JSON = """
108
 
[
109
 
    {
110
 
        "token": "ABCDEF01234token",
111
 
        "description": "Ubuntu One @ darkstar",
112
 
        "kind": "Computer"
113
 
    },
114
 
    {
115
 
        "token": "ABC1234DEF",
116
 
        "description": "Ubuntu One @ localhost",
117
 
        "kind": "Computer"
118
 
    },
119
 
    {
120
 
        "kind": "Phone",
121
 
        "description": "Nokia E65",
122
 
        "id": 1000
123
 
    }
124
 
]
125
 
"""
126
 
 
127
 
EXPECTED_DEVICES_INFO = [
128
 
    {
129
 
        "device_id": "ComputerABCDEF01234token",
130
 
        "name": "Ubuntu One @ darkstar",
131
 
        "type": "Computer",
132
 
        "is_local": '',
133
 
        "configurable": '',
134
 
    },
135
 
    {
136
 
        'is_local': 'True',
137
 
        'configurable': 'True',
138
 
        'device_id': 'ComputerABC1234DEF',
139
 
        'limit_bandwidth': '',
140
 
        'max_download_speed': '-1',
141
 
        'max_upload_speed': '-1',
142
 
        'name': 'Ubuntu One @ localhost',
143
 
        'type': 'Computer'
144
 
    },
145
 
    {
146
 
        "device_id": "Phone1000",
147
 
        "name": "Nokia E65",
148
 
        "type": "Phone",
149
 
        "configurable": '',
150
 
        "is_local": '',
151
 
    },
152
 
]
153
 
 
154
 
SAMPLE_FOLDERS = [
155
 
    {u'generation': u'2', u'node_id': u'341da068-81d8-437a-8f75-5bb9d86455ba',
156
 
     u'path': u'/home/tester/Public', u'subscribed': u'True',
157
 
     u'suggested_path': u'~/Public',
158
 
     u'type': u'UDF', u'volume_id': u'9ea892f8-15fa-4201-bdbf-8de99fa5f588'},
159
 
    {u'generation': u'', u'node_id': u'11fbc86c-0d7a-49f5-ae83-8402caf66c6a',
160
 
     u'path': u'/home/tester/Documents', u'subscribed': u'',
161
 
     u'suggested_path': u'~/Documents',
162
 
     u'type': u'UDF', u'volume_id': u'2db262f5-a151-4c19-969c-bb5ced753c61'},
163
 
    {u'generation': u'24', u'node_id': u'9ee0e130-a7c7-4d76-a5e3-5df506221b48',
164
 
     u'path': u'/home/tester/Pictures/Photos', u'subscribed': u'True',
165
 
     u'suggested_path': u'~/Pictures/Photos',
166
 
     u'type': u'UDF', u'volume_id': u'1deb2874-3d28-46ae-9999-d5f48de9f460'},
167
 
]
168
 
 
169
 
SAMPLE_SHARES = [
170
 
    {u'accepted': u'True', u'access_level': u'View',
171
 
     u'free_bytes': u'39892622746', u'generation': u'2704',
172
 
     u'name': u're', u'node_id': u'c483f419-ed28-490a-825d-a8c074e2d795',
173
 
     u'other_username': u'otheruser', u'other_visible_name': u'Other User',
174
 
     u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User',
175
 
     u'type': u'Share', u'volume_id': u'4a1b263b-a2b3-4f66-9e66-4cd18050810d'},
176
 
    {u'accepted': u'True', u'access_level': u'Modify',
177
 
     u'free_bytes': u'39892622746', u'generation': u'2704',
178
 
     u'name': u'do', u'node_id': u'84544ea4-aefe-4f91-9bb9-ed7b0a805baf',
179
 
     u'other_username': u'otheruser', u'other_visible_name': u'Other User',
180
 
     u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User',
181
 
     u'type': u'Share', u'volume_id': u'7d130dfe-98b2-4bd5-8708-9eeba9838ac0'},
182
 
]
183
 
 
184
 
SAMPLE_SHARED = [
185
 
    {u'accepted': u'True', u'access_level': u'View',
186
 
     u'free_bytes': u'', u'generation': u'',
187
 
     u'name': u'bar', u'node_id': u'31e47530-9448-4f03-b4dc-4154fdf35225',
188
 
     u'other_username': u'otheruser', u'other_visible_name': u'Other User',
189
 
     u'path': u'/home/tester/Ubuntu One/bar',
190
 
     u'type': u'Shared',
191
 
     u'volume_id': u'79584900-517f-4dff-b2f3-20e8c1e79365'},
192
 
]
193
 
 
194
55
 
195
56
class MockWebClient(object):
196
57
    """A mock webclient."""
213
74
class MockDBusClient(object):
214
75
    """A mock dbus_client module."""
215
76
 
216
 
    creds = SAMPLE_CREDENTIALS
 
77
    creds = TOKEN
217
78
    throttling = False
218
79
    limits = {"download": -1, "upload": -1}
219
80
    file_sync = True
257
118
 
258
119
    def files_sync_enabled(self):
259
120
        """Get if file sync service is enabled."""
260
 
        return self.file_sync
 
121
        return MockDBusClient.file_sync
261
122
 
262
123
    def set_files_sync_enabled(self, enabled):
263
124
        """Set the file sync service to be 'enabled'."""
264
 
        self.file_sync = enabled
 
125
        MockDBusClient.file_sync = enabled
265
126
 
266
127
    def get_folders(self):
267
128
        """Grab list of folders."""
292
153
        return SAMPLE_SHARED
293
154
 
294
155
 
 
156
class MockReplicationClient(object):
 
157
    """A mock replication_client module."""
 
158
 
 
159
    BOOKMARKS = 'awesome'
 
160
    CONTACTS = 'legendary'
 
161
 
 
162
    replications = set([BOOKMARKS, CONTACTS, 'other'])
 
163
    exclusions = set([CONTACTS])
 
164
 
 
165
    def get_replications(self):
 
166
        """Grab the list of replications in this machine."""
 
167
        return MockReplicationClient.replications
 
168
 
 
169
    def get_exclusions(self):
 
170
        """Grab the list of exclusions in this machine."""
 
171
        return MockReplicationClient.exclusions
 
172
 
 
173
    def replicate(self, replication_id):
 
174
        """Remove replication_id from the exclusions list."""
 
175
        if replication_id not in MockReplicationClient.replications:
 
176
            raise replication_client.ReplicationError(replication_id)
 
177
        MockReplicationClient.exclusions.remove(replication_id)
 
178
 
 
179
    def exclude(self, replication_id):
 
180
        """Add replication_id to the exclusions list."""
 
181
        if replication_id not in MockReplicationClient.replications:
 
182
            raise replication_client.ReplicationError(replication_id)
 
183
        MockReplicationClient.exclusions.add(replication_id)
 
184
 
 
185
 
295
186
class BackendBasicTestCase(TestCase):
296
187
    """Simple tests for the backend."""
297
188
 
301
192
        super(BackendBasicTestCase, self).setUp()
302
193
        self.patch(backend, "WebClient", MockWebClient)
303
194
        self.patch(backend, "dbus_client", MockDBusClient())
304
 
        self.local_token = "Computer" + SAMPLE_CREDENTIALS["token"]
 
195
        self.patch(backend, "replication_client", MockReplicationClient())
 
196
        self.local_token = "Computer" + TOKEN["token"]
305
197
        self.be = backend.ControlBackend()
306
198
 
307
199
        self.memento = MementoHandler()
308
200
        backend.logger.addHandler(self.memento)
309
201
 
310
 
        MockDBusClient.creds = SAMPLE_CREDENTIALS
 
202
        MockDBusClient.creds = TOKEN
311
203
 
312
204
    def test_backend_creation(self):
313
205
        """The backend instance is successfully created."""
317
209
    def test_get_token(self):
318
210
        """The get_token method returns the right token."""
319
211
        token = yield self.be.get_token()
320
 
        self.assertEqual(token, SAMPLE_CREDENTIALS["token"])
 
212
        self.assertEqual(token, TOKEN["token"])
321
213
 
322
214
    @inlineCallbacks
323
215
    def test_device_is_local(self):
388
280
        result = yield self.be.remove_device(device_id)
389
281
        self.assertEqual(result, device_id)
390
282
        # credentials were not cleared
391
 
        self.assertEqual(MockDBusClient.creds, SAMPLE_CREDENTIALS)
 
283
        self.assertEqual(MockDBusClient.creds, TOKEN)
392
284
 
393
285
    @inlineCallbacks
394
286
    def test_remove_device_clear_credentials_if_local_device(self):
395
287
        """The remove_device method clears the credentials if is local."""
396
 
        apiurl = DEVICE_REMOVE_API % ('computer', SAMPLE_CREDENTIALS['token'])
 
288
        apiurl = DEVICE_REMOVE_API % ('computer', TOKEN['token'])
397
289
        # pylint: disable=E1101
398
290
        self.be.wc.results[apiurl] = SAMPLE_DEVICES_JSON
399
291
        yield self.be.remove_device(self.local_token)
487
379
        """The volume settings can be changed."""
488
380
        fid = '0123-4567'
489
381
 
490
 
        yield self.be.change_volume_settings(fid, {'subscribed': True})
 
382
        yield self.be.change_volume_settings(fid, {'subscribed': 'True'})
491
383
        self.assertEqual(MockDBusClient.subscribed_folders, [fid])
492
384
 
493
 
        yield self.be.change_volume_settings(fid, {'subscribed': False})
 
385
        yield self.be.change_volume_settings(fid, {'subscribed': ''})
494
386
        self.assertEqual(MockDBusClient.subscribed_folders, [])
495
387
 
496
388
    @inlineCallbacks
653
545
        # Access to a protected member _process_file_sync_status
654
546
        expected_status = self.be._process_file_sync_status(status)
655
547
        self.assertEqual(self._called, ((expected_status,), {}))
 
548
 
 
549
 
 
550
class BackendSyncEnabledTestCase(BackendBasicTestCase):
 
551
    """Syncdaemon enable/disable for the backend."""
 
552
 
 
553
    def test_enable_files(self):
 
554
        """Files service is enabled."""
 
555
        self.be.disable_files()
 
556
 
 
557
        self.be.enable_files()
 
558
        self.assertTrue(MockDBusClient.file_sync)
 
559
 
 
560
    def test_disable_files(self):
 
561
        """Files service is disabled."""
 
562
        self.be.enable_files()
 
563
 
 
564
        self.be.disable_files()
 
565
        self.assertFalse(MockDBusClient.file_sync)
 
566
 
 
567
 
 
568
class BackendReplicationsTestCase(BackendBasicTestCase):
 
569
    """Replications tests for the backend."""
 
570
 
 
571
    @inlineCallbacks
 
572
    def test_replications_info(self):
 
573
        """The replications_info method exercises its callback."""
 
574
        result = yield self.be.replications_info()
 
575
 
 
576
        # replications_info will use exclusions information
 
577
        expected = []
 
578
        for name in MockReplicationClient.replications:
 
579
            enabled = bool_str(name not in MockReplicationClient.exclusions)
 
580
            dependency = ''
 
581
            if name == MockReplicationClient.BOOKMARKS:
 
582
                dependency = backend.BOOKMARKS_PKG
 
583
            elif name == MockReplicationClient.CONTACTS:
 
584
                dependency = backend.CONTACTS_PKG
 
585
 
 
586
            item = {'replication_id': name, 'name': name,
 
587
                    'enabled': enabled, 'dependency': dependency}
 
588
            expected.append(item)
 
589
        self.assertEqual(sorted(expected), sorted(result))
 
590
 
 
591
    @inlineCallbacks
 
592
    def test_change_replication_settings(self):
 
593
        """The replication settings can be changed."""
 
594
        rid = '0123-4567'
 
595
        MockReplicationClient.replications.add(rid)
 
596
        self.addCleanup(lambda: MockReplicationClient.replications.remove(rid))
 
597
 
 
598
        yield self.be.change_replication_settings(rid, {'enabled': ''})
 
599
        self.assertIn(rid, MockReplicationClient.exclusions)
 
600
 
 
601
        yield self.be.change_replication_settings(rid, {'enabled': 'True'})
 
602
        self.assertNotIn(rid, MockReplicationClient.exclusions)
 
603
 
 
604
    @inlineCallbacks
 
605
    def test_change_replication_settings_not_in_replications(self):
 
606
        """The settings can not be changed for an item not in replications."""
 
607
        rid = '0123-4567'
 
608
        assert rid not in MockReplicationClient.replications
 
609
 
 
610
        d = self.be.change_replication_settings(rid, {'enabled': 'True'})
 
611
        yield self.assertFailure(d, replication_client.ReplicationError)
 
612
 
 
613
        d = self.be.change_replication_settings(rid, {'enabled': ''})
 
614
        yield self.assertFailure(d, replication_client.ReplicationError)
 
615
 
 
616
    @inlineCallbacks
 
617
    def test_change_replication_settings_no_setting(self):
 
618
        """The change replication settings does not fail on empty settings."""
 
619
        rid = '0123-4567'
 
620
        MockReplicationClient.replications.add(rid)
 
621
        self.addCleanup(lambda: MockReplicationClient.replications.remove(rid))
 
622
 
 
623
        prior = MockReplicationClient.exclusions.copy()
 
624
        yield self.be.change_replication_settings(rid, {})
 
625
 
 
626
        self.assertEqual(MockReplicationClient.exclusions, prior)