1
# ubuntuone.syncdaemon.tests.test_pathlockingtree - PathLockingTree tests
3
# Author: Facundo Batista <facundo@canonical.com>
5
# Copyright 2011 Canonical Ltd.
7
# This program is free software: you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License version 3, as published
9
# by the Free Software Foundation.
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranties of
13
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14
# PURPOSE. See the GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License along
17
# with this program. If not, see <http://www.gnu.org/licenses/>.
18
""" ActionQueue tests """
22
from twisted.internet import defer
23
from twisted.trial.unittest import TestCase as TwistedTestCase
25
from ubuntuone.devtools.handlers import MementoHandler
26
from ubuntuone.syncdaemon.action_queue import PathLockingTree
29
class InternalDeferredTests(TwistedTestCase):
30
"""Test the internal deferreds handling functionality."""
34
self.plt = PathLockingTree()
36
def test_single_element_old(self):
37
"""Add to a single element that was there."""
38
self.plt.acquire('path')
39
self.plt.acquire('path')
41
# root has only one child
42
self.assertEqual(len(self.plt.root['children_nodes']), 1)
43
child = self.plt.root['children_nodes']['path']
45
# child has right values
46
self.assertEqual(len(child['children_nodes']), 0)
47
self.assertEqual(len(child['children_deferreds']), 0)
48
self.assertEqual(len(child['node_deferreds']), 2)
50
def test_single_element_new(self):
51
"""Add a single element that is new."""
52
self.plt.acquire('path')
54
# root has only one child
55
self.assertEqual(len(self.plt.root['children_nodes']), 1)
56
child = self.plt.root['children_nodes']['path']
58
# child has right values
59
self.assertEqual(len(child['children_nodes']), 0)
60
self.assertEqual(len(child['children_deferreds']), 0)
61
self.assertEqual(len(child['node_deferreds']), 1)
63
def test_two_element_both_old(self):
64
"""Add to two already there elements."""
65
self.plt.acquire('path1', 'path2')
66
self.plt.acquire('path1', 'path2')
68
# root has only one child
69
self.assertEqual(len(self.plt.root['children_nodes']), 1)
70
child = self.plt.root['children_nodes']['path1']
72
# root's child has right values
73
self.assertEqual(len(child['children_nodes']), 1)
74
self.assertEqual(len(child['children_deferreds']), 2)
75
self.assertEqual(len(child['node_deferreds']), 0)
77
# root's grandchild has right values
78
child = child['children_nodes']['path2']
79
self.assertEqual(len(child['children_nodes']), 0)
80
self.assertEqual(len(child['children_deferreds']), 0)
81
self.assertEqual(len(child['node_deferreds']), 2)
83
def test_two_element_both_new(self):
84
"""Add to two new elements."""
85
self.plt.acquire('path1', 'path2')
87
# root has only one child
88
self.assertEqual(len(self.plt.root['children_nodes']), 1)
89
child = self.plt.root['children_nodes']['path1']
91
# root's child has right values
92
self.assertEqual(len(child['children_nodes']), 1)
93
self.assertEqual(len(child['children_deferreds']), 1)
94
self.assertEqual(len(child['node_deferreds']), 0)
96
# root's grandchild has right values
97
child = child['children_nodes']['path2']
98
self.assertEqual(len(child['children_nodes']), 0)
99
self.assertEqual(len(child['children_deferreds']), 0)
100
self.assertEqual(len(child['node_deferreds']), 1)
102
def test_two_element_mixed(self):
103
"""Add to one new and one old elements."""
105
self.plt.acquire('path1')
107
# root has only one child
108
self.assertEqual(len(self.plt.root['children_nodes']), 1)
109
child = self.plt.root['children_nodes']['path1']
111
# root's child has right values
112
self.assertEqual(len(child['children_nodes']), 0)
113
self.assertEqual(len(child['children_deferreds']), 0)
114
self.assertEqual(len(child['node_deferreds']), 1)
117
self.plt.acquire('path1', 'path2')
119
# root's child has right values
120
self.assertEqual(len(child['children_nodes']), 1)
121
self.assertEqual(len(child['children_deferreds']), 1)
122
self.assertEqual(len(child['node_deferreds']), 1)
124
# root's grandchild has right values
125
child = child['children_nodes']['path2']
126
self.assertEqual(len(child['children_nodes']), 0)
127
self.assertEqual(len(child['children_deferreds']), 0)
128
self.assertEqual(len(child['node_deferreds']), 1)
130
def test_element_to_longer_branch(self):
131
"""Add element in the middle of longer branch."""
132
# first a long one, then a shorter one
133
self.plt.acquire(*"abc")
134
self.plt.acquire("a")
136
# root has only one child
137
self.assertEqual(len(self.plt.root['children_nodes']), 1)
138
child = self.plt.root['children_nodes']['a']
140
# root's child has right values
141
self.assertEqual(len(child['children_nodes']), 1)
142
self.assertEqual(len(child['children_deferreds']), 1)
143
self.assertEqual(len(child['node_deferreds']), 1)
145
# root's grandchild has right values
146
child = child['children_nodes']['b']
147
self.assertEqual(len(child['children_nodes']), 1)
148
self.assertEqual(len(child['children_deferreds']), 1)
149
self.assertEqual(len(child['node_deferreds']), 0)
151
# root's grandgrandchild has right values
152
child = child['children_nodes']['c']
153
self.assertEqual(len(child['children_nodes']), 0)
154
self.assertEqual(len(child['children_deferreds']), 0)
155
self.assertEqual(len(child['node_deferreds']), 1)
157
def test_second_to_root(self):
158
"""Add other root child."""
159
self.plt.acquire("path1")
160
self.plt.acquire("path2")
162
# root has two children
163
self.assertEqual(len(self.plt.root['children_nodes']), 2)
165
# root's child 1 has right values
166
child = self.plt.root['children_nodes']['path1']
167
self.assertEqual(len(child['children_nodes']), 0)
168
self.assertEqual(len(child['children_deferreds']), 0)
169
self.assertEqual(len(child['node_deferreds']), 1)
171
# root's child 2 has right values
172
child = self.plt.root['children_nodes']['path2']
173
self.assertEqual(len(child['children_nodes']), 0)
174
self.assertEqual(len(child['children_deferreds']), 0)
175
self.assertEqual(len(child['node_deferreds']), 1)
177
def test_diverging_branch(self):
178
"""Add a branch that separates from other."""
179
# first a long one, then a shorter one
180
self.plt.acquire(*"abcd")
181
self.plt.acquire(*"abj")
183
# root has only one child
184
self.assertEqual(len(self.plt.root['children_nodes']), 1)
187
node_a = self.plt.root['children_nodes']['a']
188
self.assertEqual(len(node_a['children_nodes']), 1)
189
self.assertEqual(len(node_a['children_deferreds']), 2)
190
self.assertEqual(len(node_a['node_deferreds']), 0)
193
node_b = node_a['children_nodes']['b']
194
self.assertEqual(len(node_b['children_nodes']), 2)
195
self.assertEqual(len(node_b['children_deferreds']), 2)
196
self.assertEqual(len(node_b['node_deferreds']), 0)
199
node_c = node_b['children_nodes']['c']
200
self.assertEqual(len(node_c['children_nodes']), 1)
201
self.assertEqual(len(node_c['children_deferreds']), 1)
202
self.assertEqual(len(node_c['node_deferreds']), 0)
205
node_d = node_c['children_nodes']['d']
206
self.assertEqual(len(node_d['children_nodes']), 0)
207
self.assertEqual(len(node_d['children_deferreds']), 0)
208
self.assertEqual(len(node_d['node_deferreds']), 1)
211
node_j = node_b['children_nodes']['j']
212
self.assertEqual(len(node_j['children_nodes']), 0)
213
self.assertEqual(len(node_j['children_deferreds']), 0)
214
self.assertEqual(len(node_j['node_deferreds']), 1)
217
class LockingTests(TwistedTestCase):
218
"""Test the locking between elements."""
222
self.plt = PathLockingTree()
224
@defer.inlineCallbacks
225
def test_none_before(self):
226
"""Not lock because nothing there before."""
227
yield self.plt.acquire("path")
229
@defer.inlineCallbacks
230
def test_same_path_one_previous(self):
231
"""Lock on same path, one previous command."""
232
release = yield self.plt.acquire("path")
233
d = self.plt.acquire("path")
235
# add func first and change value later, to check when released
236
d.addCallback(lambda _: self.assertTrue(was_later))
242
@defer.inlineCallbacks
243
def test_same_path_two_previous(self):
244
"""Lock on same path, two previous commands."""
246
d1 = self.plt.acquire("path")
247
d1.addCallback(releases.append)
248
d2 = self.plt.acquire("path")
249
d2.addCallback(releases.append)
251
# add func first, test all releases were made before the check
252
d3 = self.plt.acquire("path")
253
d3.addCallback(lambda _: self.assertFalse(releases))
259
@defer.inlineCallbacks
260
def test_same_path_having_parent(self):
261
"""Lock with parent having just the parent."""
262
yield self.plt.acquire("path1")
263
yield self.plt.acquire("path1", "path2")
265
@defer.inlineCallbacks
266
def test_same_path_having_children(self):
267
"""Lock with parent having just the parent."""
268
yield self.plt.acquire("path1", "path2", "path3")
269
yield self.plt.acquire("path1", "path2")
271
@defer.inlineCallbacks
272
def test_with_parent_none(self):
273
"""Lock with parent but empty."""
274
yield self.plt.acquire("path", on_parent=True)
276
@defer.inlineCallbacks
277
def test_with_parent_just_parent(self):
278
"""Lock with parent having just the parent."""
279
release = yield self.plt.acquire("path1")
280
d = self.plt.acquire("path1", "path2", on_parent=True)
282
# add func first and change value later, to check when released
283
d.addCallback(lambda _: self.assertTrue(was_later))
289
@defer.inlineCallbacks
290
def test_with_parent_having_same(self):
291
"""Lock with parent having also the same path."""
293
d = self.plt.acquire(*"abc")
294
d.addCallback(releases.append)
295
d = self.plt.acquire(*"abcd")
296
d.addCallback(releases.append)
298
# add func first, test all releases were made before the check
299
d = self.plt.acquire(*"abcd", on_parent=True)
300
d.addCallback(lambda _: self.assertFalse(releases))
306
@defer.inlineCallbacks
307
def test_with_parent_multiple(self):
308
"""Lock with some commands in parent and same."""
310
d = self.plt.acquire(*"abcd")
311
d.addCallback(releases.append)
312
d = self.plt.acquire(*"abcd")
313
d.addCallback(releases.append)
314
d = self.plt.acquire(*"abc")
315
d.addCallback(releases.append)
316
d = self.plt.acquire(*"abc")
317
d.addCallback(releases.append)
319
# add func first, test all releases were made before the check
320
d = self.plt.acquire(*"abcd", on_parent=True)
321
d.addCallback(lambda _: self.assertFalse(releases))
329
@defer.inlineCallbacks
330
def test_with_parent_having_just_children(self):
331
"""Lock with parent but only has children."""
332
yield self.plt.acquire("path1", "path2", "path3")
333
yield self.plt.acquire("path1", "path2", on_parent=True)
335
@defer.inlineCallbacks
336
def test_with_children_none(self):
337
"""Lock with children but empty."""
338
yield self.plt.acquire("path", on_children=True)
340
@defer.inlineCallbacks
341
def test_with_children_just_children(self):
342
"""Lock with children having just a child."""
343
release = yield self.plt.acquire("path1", "path2")
344
d = self.plt.acquire("path1", on_children=True)
346
# add func first and change value later, to check when released
347
d.addCallback(lambda _: self.assertTrue(was_later))
353
@defer.inlineCallbacks
354
def test_with_children_having_same(self):
355
"""Lock with children having also the same path."""
357
d = self.plt.acquire(*"ab")
358
d.addCallback(releases.append)
359
d = self.plt.acquire(*"abc")
360
d.addCallback(releases.append)
362
# add func first, test all releases were made before the check
363
d = self.plt.acquire(*"ab", on_children=True)
364
d.addCallback(lambda _: self.assertFalse(releases))
370
@defer.inlineCallbacks
371
def test_with_children_multiple(self):
372
"""Lock with some commands in children and same."""
374
d = self.plt.acquire(*"ab")
375
d.addCallback(releases.append)
376
d = self.plt.acquire(*"ab")
377
d.addCallback(releases.append)
378
d = self.plt.acquire(*"abc")
379
d.addCallback(releases.append)
380
d = self.plt.acquire(*"abc")
381
d.addCallback(releases.append)
383
# add func first, test all releases were made before the check
384
d = self.plt.acquire(*"ab", on_children=True)
385
d.addCallback(lambda _: self.assertFalse(releases))
393
@defer.inlineCallbacks
394
def test_with_children_and_parent_all_mixed(self):
395
"""Lock with some commands everywhere, :p."""
397
d = self.plt.acquire(*"ab")
398
d.addCallback(releases.append)
399
d = self.plt.acquire(*"abc")
400
d.addCallback(releases.append)
401
d = self.plt.acquire(*"abc")
402
d.addCallback(releases.append)
403
d = self.plt.acquire(*"a")
404
d.addCallback(releases.append)
406
# add func first, test all releases were made before the check
407
d = self.plt.acquire(*"ab", on_children=True, on_parent=True)
408
d.addCallback(lambda _: self.assertFalse(releases))
417
class CleaningTests(TwistedTestCase):
418
"""Test that the releases clean the tree."""
422
self.plt = PathLockingTree()
424
@defer.inlineCallbacks
425
def test_simple(self):
426
"""Simple clean, add one, release it."""
427
release = yield self.plt.acquire("path")
429
self.assertEqual(len(self.plt.root['children_nodes']), 0)
431
@defer.inlineCallbacks
432
def test_add_two_release_one(self):
433
"""Add two different paths, release them by one."""
434
release1 = yield self.plt.acquire("path1")
435
release2 = yield self.plt.acquire("path2")
436
self.assertEqual(len(self.plt.root['children_nodes']), 2)
439
self.assertEqual(len(self.plt.root['children_nodes']), 1)
442
self.assertEqual(len(self.plt.root['children_nodes']), 0)
444
@defer.inlineCallbacks
445
def test_longer_branch(self):
446
"""Simple clean, but using a longer branch."""
447
release = yield self.plt.acquire(*"abc")
449
self.assertEqual(len(self.plt.root['children_nodes']), 0)
451
@defer.inlineCallbacks
452
def test_overlapped_release_shorter(self):
453
"""Overlap two paths, release shorter."""
454
release1 = yield self.plt.acquire(*"abc")
455
release2 = yield self.plt.acquire(*"ab")
457
# release shorter, check structure
459
self.assertEqual(len(self.plt.root['children_nodes']), 1)
460
node_a = self.plt.root['children_nodes']['a']
461
self.assertEqual(len(node_a['children_nodes']), 1)
462
self.assertEqual(len(node_a['children_deferreds']), 1)
463
self.assertEqual(len(node_a['node_deferreds']), 0)
464
node_b = node_a['children_nodes']['b']
465
self.assertEqual(len(node_b['children_nodes']), 1)
466
self.assertEqual(len(node_b['children_deferreds']), 1)
467
self.assertEqual(len(node_b['node_deferreds']), 0)
468
node_c = node_b['children_nodes']['c']
469
self.assertEqual(len(node_c['children_nodes']), 0)
470
self.assertEqual(len(node_c['children_deferreds']), 0)
471
self.assertEqual(len(node_c['node_deferreds']), 1)
473
# release longer, empty now!
475
self.assertEqual(len(self.plt.root['children_nodes']), 0)
477
@defer.inlineCallbacks
478
def test_overlapped_release_longer(self):
479
"""Overlap two paths, release longer."""
480
release1 = yield self.plt.acquire(*"abc")
481
release2 = yield self.plt.acquire(*"ab")
483
# release longer, check structure
485
self.assertEqual(len(self.plt.root['children_nodes']), 1)
486
node_a = self.plt.root['children_nodes']['a']
487
self.assertEqual(len(node_a['children_nodes']), 1)
488
self.assertEqual(len(node_a['children_deferreds']), 1)
489
self.assertEqual(len(node_a['node_deferreds']), 0)
490
node_b = node_a['children_nodes']['b']
491
self.assertEqual(len(node_b['children_nodes']), 0)
492
self.assertEqual(len(node_b['children_deferreds']), 0)
493
self.assertEqual(len(node_b['node_deferreds']), 1)
495
# release shorter, empty now!
497
self.assertEqual(len(self.plt.root['children_nodes']), 0)
499
@defer.inlineCallbacks
500
def test_same_long_path_double(self):
501
"""Two long branchs."""
502
release1 = yield self.plt.acquire(*"ab")
505
d = self.plt.acquire(*"ab")
506
d.addCallback(releases.append)
508
# release first, check structure
510
self.assertEqual(len(self.plt.root['children_nodes']), 1)
511
node_a = self.plt.root['children_nodes']['a']
512
self.assertEqual(len(node_a['children_nodes']), 1)
513
self.assertEqual(len(node_a['children_deferreds']), 1)
514
self.assertEqual(len(node_a['node_deferreds']), 0)
515
node_b = node_a['children_nodes']['b']
516
self.assertEqual(len(node_b['children_nodes']), 0)
517
self.assertEqual(len(node_b['children_deferreds']), 0)
518
self.assertEqual(len(node_b['node_deferreds']), 1)
520
# release second, empty now!
522
self.assertEqual(len(self.plt.root['children_nodes']), 0)
524
@defer.inlineCallbacks
525
def test_diverging_branch(self):
526
"""Diverging branches."""
527
release1 = yield self.plt.acquire(*"abc")
528
release2 = yield self.plt.acquire(*"aj")
530
# release longer, check structure
532
self.assertEqual(len(self.plt.root['children_nodes']), 1)
533
node_a = self.plt.root['children_nodes']['a']
534
self.assertEqual(len(node_a['children_nodes']), 1)
535
self.assertEqual(len(node_a['children_deferreds']), 1)
536
self.assertEqual(len(node_a['node_deferreds']), 0)
537
node_j = node_a['children_nodes']['j']
538
self.assertEqual(len(node_j['children_nodes']), 0)
539
self.assertEqual(len(node_j['children_deferreds']), 0)
540
self.assertEqual(len(node_j['node_deferreds']), 1)
542
# release second, empty now!
544
self.assertEqual(len(self.plt.root['children_nodes']), 0)
547
class LoggingTests(TwistedTestCase):
548
"""Test the logging."""
552
self.plt = PathLockingTree()
554
self.handler = MementoHandler()
555
self.plt.logger.addHandler(self.handler)
557
@defer.inlineCallbacks
558
def test_logger_can_be_given(self):
559
"""Accept an external logger."""
560
logger = logging.getLogger("ubuntuone.SyncDaemon.Test")
561
handler = MementoHandler()
562
logger.addHandler(handler)
565
release = yield self.plt.acquire('path', logger=logger)
566
self.assertTrue(handler.check_debug("acquiring on"))
570
self.assertTrue(handler.check_debug("releasing"))
573
def test_acquire_single_default(self):
574
"""Single path, full check."""
575
self.plt.acquire('path')
576
self.assertTrue(self.handler.check_debug(
577
"acquiring on", "path",
578
"(on_parent=False, on_children=False)", "wait for: 0"))
580
def test_acquire_single_on_parent(self):
581
"""Single path, on parent."""
582
self.plt.acquire('path', on_parent=True)
583
self.assertTrue(self.handler.check_debug("on_parent=True"))
585
def test_acquire_single_on_children(self):
586
"""Single path, on children."""
587
self.plt.acquire('path', on_children=True)
588
self.assertTrue(self.handler.check_debug("on_children=True"))
590
def test_acquire_single_on_both(self):
591
"""Single path, on both."""
592
self.plt.acquire('path', on_parent=True, on_children=True)
593
self.assertTrue(self.handler.check_debug(
594
"(on_parent=True, on_children=True)"))
596
def test_acquire_multiple(self):
597
"""Single path, on both."""
598
self.plt.acquire('1', '2', *"abc")
599
self.assertTrue(self.handler.check_debug("'1', '2', 'a', 'b', 'c'"))
601
def test_acquire_waiting(self):
602
"""Single path, on both."""
603
self.plt.acquire('path')
604
self.assertTrue(self.handler.check_debug("wait for: 0"))
606
self.plt.acquire('path')
607
self.assertTrue(self.handler.check_debug("wait for: 1"))
609
self.plt.acquire('path')
610
self.assertTrue(self.handler.check_debug("wait for: 2"))
612
@defer.inlineCallbacks
613
def test_release_simple(self):
614
"""Single release."""
615
release = yield self.plt.acquire("path")
617
self.assertTrue(self.handler.check_debug("releasing",
618
"path", "remaining: 0"))
620
@defer.inlineCallbacks
621
def test_release_double(self):
622
"""Double release."""
623
release1 = yield self.plt.acquire("path1")
624
release2 = yield self.plt.acquire("path2")
626
self.assertTrue(self.handler.check_debug("releasing",
627
"path1", "remaining: 1"))
629
self.assertTrue(self.handler.check_debug("releasing",
630
"path2", "remaining: 0"))
632
@defer.inlineCallbacks
633
def test_release_longer_branches(self):
634
"""Longer branches."""
635
release = yield self.plt.acquire(*"abcde")
636
self.plt.acquire(*"abc")
637
self.plt.acquire(*"abcdefg")
638
self.plt.acquire(*"abklop")
639
self.plt.acquire(*"foobar")
641
self.assertTrue(self.handler.check_debug("releasing",
642
"'a', 'b', 'c', 'd', 'e'",