~ubuntu-branches/ubuntu/oneiric/ubuntuone-client/oneiric

« back to all changes in this revision

Viewing changes to tests/syncdaemon/test_sync.py

  • Committer: Bazaar Package Importer
  • Author(s): Rodney Dawes
  • Date: 2010-06-08 17:31:18 UTC
  • mto: This revision was merged to the branch mainline in revision 31.
  • Revision ID: james.westby@ubuntu.com-20100608173118-o8s897ll11rtne99
Tags: upstream-1.3.0
ImportĀ upstreamĀ versionĀ 1.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
from contrib.testing.testcase import (
31
31
    FakeVolumeManager,
32
32
    BaseTwistedTestCase,
33
 
    MementoHandler, DummyClass
 
33
    MementoHandler
34
34
)
35
35
 
 
36
from contrib.testing import testcase
36
37
from ubuntuone.syncdaemon.dbus_interface import DBusInterface
37
38
from ubuntuone.syncdaemon.filesystem_manager import FileSystemManager
 
39
from ubuntuone.syncdaemon.fsm import fsm as fsm_module
38
40
from ubuntuone.syncdaemon.main import Main
39
41
from ubuntuone.syncdaemon.sync import FSKey, Sync, SyncStateMachineRunner
40
42
from ubuntuone.syncdaemon.volume_manager import Share
180
182
                             self.fsm.get_by_path(path).server_hash)
181
183
 
182
184
 
183
 
class TestSync(BaseTwistedTestCase):
184
 
    """Test for Sync."""
 
185
class BaseSync(BaseTwistedTestCase):
 
186
    """Base test infrastructure for Sync."""
185
187
 
186
188
    def setUp(self):
187
189
        """Init."""
218
220
                raise exc_info[0], exc_info[1], exc_info[2]
219
221
        BaseTwistedTestCase.tearDown(self)
220
222
 
 
223
 
 
224
class TestSync(BaseSync):
 
225
    """Test for Sync."""
 
226
 
221
227
    def test_deleting_open_files_is_no_cause_for_despair(self):
222
228
        """test_deleting_open_files_is_no_cause_for_despair."""
223
229
        def cb(_):
256
262
        def faked_nothing(ssmr, event, params, *args):
257
263
            """Wrap SSMR.nothing to test."""
258
264
            self.called = True
 
265
        self.patch(SyncStateMachineRunner, 'nothing', faked_nothing)
259
266
 
260
 
        SyncStateMachineRunner.nothing = faked_nothing
261
267
        kwargs = dict(share_id='share_id', node_id='node_id')
262
268
        sync.handle_AQ_DOWNLOAD_DOES_NOT_EXIST(**kwargs)
263
269
        self.assertTrue(self.called, 'nothing was called')
264
270
 
265
 
 
266
 
class SyncStateMachineRunnerTestCase(BaseTwistedTestCase):
 
271
    def test_handle_FILE_CREATE_while_LOCAL(self):
 
272
        """A FS_FILE_CREATE is received with the node in LOCAL."""
 
273
        sync = Sync(main=self.main)
 
274
        self.called = False
 
275
 
 
276
        def faked_nothing(ssmr, event, params, *args):
 
277
            """Wrap SSMR.nothing to test."""
 
278
            self.called = True
 
279
        self.patch(SyncStateMachineRunner, 'nothing', faked_nothing)
 
280
 
 
281
        # create a file and put it in local
 
282
        fsm = self.main.fs
 
283
        somepath = os.path.join(self.root, 'somepath')
 
284
        mdid = fsm.create(somepath, '')
 
285
        fsm.set_by_mdid(mdid, local_hash='somehash')
 
286
 
 
287
        # send the event, and check that it called its .nothing()
 
288
        sync.handle_FS_FILE_CREATE(somepath)
 
289
        self.assertTrue(self.called)
 
290
 
 
291
    def test_SV_HASH_NEW_with_file_uploadinterrupted(self):
 
292
        """A SV_HASH_NEW is received after upload interrupted."""
 
293
        sync = Sync(main=self.main)
 
294
        self.called = False
 
295
 
 
296
        def fake_meth(_, event, params, hash):
 
297
            """Wrap SSMR.reput_file_from_local to test."""
 
298
            self.assertEqual(event, 'SV_HASH_NEW')
 
299
            self.assertEqual(hash, '')
 
300
            self.called = True
 
301
        self.patch(SyncStateMachineRunner, 'reput_file_from_local', fake_meth)
 
302
 
 
303
        # create a file and put it in local, without server_hash, as
 
304
        # if the upload was cut in the middle after the make file
 
305
        fsm = self.main.fs
 
306
        somepath = os.path.join(self.root, 'somepath')
 
307
        mdid = fsm.create(somepath, '', node_id='node_id')
 
308
        fsm.set_by_mdid(mdid, local_hash='somehash', crc32='crc32',
 
309
                        stat='stat', size='size')
 
310
 
 
311
        # send the event and check
 
312
        mdobj = fsm.get_by_mdid(mdid)
 
313
        sync.handle_SV_HASH_NEW(mdobj.share_id, mdobj.node_id, '') # no content
 
314
        self.assertTrue(self.called)
 
315
 
 
316
 
 
317
class SyncStateMachineRunnerTestCase(BaseSync):
267
318
    """Tests for the SyncStateMachineRunner."""
268
319
 
269
320
    def setUp(self):
270
321
        """Init."""
271
 
        BaseTwistedTestCase.setUp(self)
272
 
        self.ssmr = SyncStateMachineRunner(fsm=None, main=None,
273
 
                                           key=DummyClass(), logger=None)
 
322
        BaseSync.setUp(self)
 
323
 
 
324
        # create a file
 
325
        self.fsm = self.main.fs
 
326
        somepath = os.path.join(self.root, 'somepath')
 
327
        self.mdid = self.fsm.create(somepath, '', node_id='node_id')
 
328
 
 
329
        key = FSKey(self.main.fs, share_id='', node_id='node_id')
 
330
        self.ssmr = SyncStateMachineRunner(fsm=self.main.fs, main=self.main,
 
331
                                           key=key, logger=None)
 
332
        self.root = self.mktemp('root')
274
333
 
275
334
    def tearDown(self):
276
335
        """Clean up."""
277
336
        self.ssmr = None
278
 
        BaseTwistedTestCase.tearDown(self)
 
337
        BaseSync.tearDown(self)
279
338
 
280
 
    def test_delete_file(self):
281
 
        """delete_file can be called with or without the server hash."""
 
339
    def test_delete_file_without_hash(self):
 
340
        """Delete_file can be called without the server hash."""
282
341
        self.ssmr.delete_file(event='AQ_DOWNLOAD_ERROR', params=None)
283
342
 
 
343
    def test_delete_file_with_hash(self):
 
344
        """Delete_file can be called with the server hash."""
284
345
        self.ssmr.delete_file(event='AQ_DOWNLOAD_ERROR', params=None,
285
346
                              server_hash='')
 
347
 
 
348
    def test_validateactualdata_log(self):
 
349
        """This method should log detailed info."""
 
350
        # create testing data
 
351
        somepath = os.path.join(self.root, 'somepath')
 
352
        open(somepath, "w").close()
 
353
        oldstat = os.stat(somepath)
 
354
        f = open(somepath, "w")
 
355
        f.write("new")
 
356
        f.close()
 
357
 
 
358
        # log config
 
359
        handler = testcase.MementoHandler()
 
360
        handler.setLevel(logging.DEBUG)
 
361
        self.ssmr.log.addHandler(handler)
 
362
 
 
363
        # call the method with args to not match
 
364
        self.ssmr.validate_actual_data(somepath, oldstat)
 
365
 
 
366
        # check log
 
367
        self.assertEqual(len(handler.records), 1)
 
368
        log_msg = handler.records[0].message
 
369
        self.assertTrue("st_ino" in log_msg)
 
370
        self.assertTrue("st_size" in log_msg)
 
371
        self.assertTrue("st_mtime" in log_msg)
 
372
        self.ssmr.log.removeHandler(handler)
 
373
 
 
374
    def test_put_file_stores_info(self):
 
375
        """The put_file method should store the info in FSM."""
 
376
        self.ssmr.put_file('HQ_HASH_NEW', None, 'hash', 'crc', 'size', 'stt')
 
377
 
 
378
        # check the info is stored
 
379
        mdobj = self.fsm.get_by_mdid(self.mdid)
 
380
        self.assertEqual(mdobj.local_hash, 'hash')
 
381
        self.assertEqual(mdobj.crc32, 'crc')
 
382
        self.assertEqual(mdobj.size, 'size')
 
383
        self.assertEqual(mdobj.stat, 'stt')
 
384
 
 
385
    def test_reput_file_stores_info(self):
 
386
        """The reput_file method should store the info in FSM."""
 
387
        self.ssmr.reput_file('HQ_HASH_NEW', None, 'hash', 'crc', 'size', 'stt')
 
388
 
 
389
        # check the info is stored
 
390
        mdobj = self.fsm.get_by_mdid(self.mdid)
 
391
        self.assertEqual(mdobj.local_hash, 'hash')
 
392
        self.assertEqual(mdobj.crc32, 'crc')
 
393
        self.assertEqual(mdobj.size, 'size')
 
394
        self.assertEqual(mdobj.stat, 'stt')
 
395
 
 
396
 
 
397
class FakedState(object):
 
398
    """A faked state."""
 
399
 
 
400
    def __init__(self, action_func):
 
401
        self.action_func = action_func
 
402
        self.values = []
 
403
 
 
404
    def get_transition(self, event_name, parameters):
 
405
        """A fake get_transition."""
 
406
        class A(object): pass
 
407
        result = A()
 
408
        result.action_func = self.action_func
 
409
        result.target = self.values
 
410
        return result
 
411
 
 
412
 
 
413
class StateMachineRunnerTestCase(BaseTwistedTestCase):
 
414
    """Test suite for StateMachineRunner."""
 
415
 
 
416
    def setUp(self):
 
417
        """Init."""
 
418
        BaseTwistedTestCase.setUp(self)
 
419
 
 
420
        logger = logging.getLogger('ubuntuone.SyncDaemon.sync')
 
421
        self.smr = fsm_module.StateMachineRunner(None, logger)
 
422
        self.handler = testcase.MementoHandler()
 
423
        self.handler.setLevel(logging.INFO)
 
424
        logger.addHandler(self.handler)
 
425
 
 
426
    def test_on_event_logs_info(self):
 
427
        """Test proper logging in on_event."""
 
428
        event_name = 'TEST_EVENT'
 
429
        parameters = object()
 
430
        action_func = 'SOME_ACTION_FUNC'
 
431
        setattr(self.smr, action_func, lambda *_: None)
 
432
        self.patch(self.smr, 'get_state', lambda: FakedState(action_func))
 
433
        self.smr.on_event(event_name=event_name, parameters=parameters)
 
434
 
 
435
        # assert over logging
 
436
        self.assertTrue(len(self.handler.records), 1)
 
437
 
 
438
        record = self.handler.records[0]
 
439
        self.assertEqual(record.levelno, logging.INFO)
 
440
 
 
441
        msg = record.message
 
442
        error = '%s must be in record.message (%s)'
 
443
        self.assertTrue(event_name in msg, error % (event_name, msg))
 
444
        self.assertTrue(str(parameters) in msg, error % (parameters, msg))
 
445
        self.assertTrue(action_func in msg, error % (action_func, msg))