import time import unittest from hydrus.core import HydrusGlobals as HG from hydrus.client import ClientThreading READ_JOB_DURATION = 0.1 WRITE_JOB_DURATION = 0.2 def do_read_job( rwlock, result_list, name ): with rwlock.read: result_list.append( 'begin read {}'.format( name ) ) time.sleep( READ_JOB_DURATION ) result_list.append( 'end read {}'.format( name ) ) def do_write_job( rwlock, result_list, name ): with rwlock.write: result_list.append( 'begin write {}'.format( name ) ) time.sleep( WRITE_JOB_DURATION ) result_list.append( 'end write {}'.format( name ) ) class TestFileRWLock( unittest.TestCase ): def test_simple( self ): rwlock = ClientThreading.FileRWLock() result_list = [] do_read_job( rwlock, result_list, '1' ) expected_result = [] expected_result.extend( [ 'begin read 1', 'end read 1' ] ) self.assertEqual( result_list, expected_result ) # result_list = [] do_write_job( rwlock, result_list, '1' ) expected_result = [] expected_result.extend( [ 'begin write 1', 'end write 1' ] ) self.assertEqual( result_list, expected_result ) def test_shared_read( self ): rwlock = ClientThreading.FileRWLock() result_list = [] HG.test_controller.CallLater( 0.0, do_read_job, rwlock, result_list, '1' ) HG.test_controller.CallLater( 0.05, do_read_job, rwlock, result_list, '2' ) time.sleep( READ_JOB_DURATION * 2 + 0.2 ) results = set( result_list ) expected_results = set() expected_results.update( [ 'begin read 1', 'end read 1' ] ) expected_results.update( [ 'begin read 2', 'end read 2' ] ) self.assertEqual( results, expected_results ) # result_list = [] for i in range( 10 ): HG.test_controller.CallLater( 0.0, do_read_job, rwlock, result_list, str( i ) ) time.sleep( READ_JOB_DURATION * 10 + 0.2 ) expected_results = set() for i in range( 10 ): expected_results.update( [ 'begin read {}'.format( i ), 'end read {}'.format( i ) ] ) results = set( result_list ) self.assertEqual( results, expected_results ) def test_competing_write( self ): rwlock = ClientThreading.FileRWLock() result_list = [] HG.test_controller.CallLater( 0.0, do_write_job, rwlock, result_list, '1' ) HG.test_controller.CallLater( 0.05, do_write_job, rwlock, result_list, '2' ) time.sleep( WRITE_JOB_DURATION * 2 + 0.2 ) expected_result = [] expected_result.extend( [ 'begin write 1', 'end write 1' ] ) expected_result.extend( [ 'begin write 2', 'end write 2' ] ) self.assertEqual( result_list, expected_result ) # result_list = [] for i in range( 10 ): HG.test_controller.CallLater( 0.0, do_write_job, rwlock, result_list, str( i ) ) time.sleep( WRITE_JOB_DURATION * 10 + 0.2 ) expected_results = set() for i in range( 10 ): expected_pair = ( 'begin write {}'.format( i ), 'end write {}'.format( i ) ) expected_results.add( expected_pair ) for i in range( 10 ): result_pair = ( result_list[ i * 2 ], result_list[ ( i * 2 ) + 1 ] ) self.assertIn( result_pair, expected_results ) def test_mixed_competing( self ): rwlock = ClientThreading.FileRWLock() result_list = [] all_expected_results = set() for i in range( 10 ): HG.test_controller.CallLater( 0.02 * i, do_read_job, rwlock, result_list, str( i ) ) all_expected_results.update( [ 'begin read {}'.format( i ), 'end read {}'.format( i ) ] ) for i in range( 5 ): HG.test_controller.CallLater( 0.05 * i, do_write_job, rwlock, result_list, str( i ) ) all_expected_results.update( [ 'begin write {}'.format( i ), 'end write {}'.format( i ) ] ) time.sleep( READ_JOB_DURATION * 10 + WRITE_JOB_DURATION * 5 + 0.2 ) self.assertEqual( set( result_list ), all_expected_results ) for i in range( 15 ): # even if reads mix up a bit, every two items should have the same read/write value a = result_list[ i * 2 ] b = result_list[ ( i * 2 ) + 1 ] if 'read' in a: self.assertIn( 'read', b ) if 'write' in a: self.assertTrue( a.startswith( 'begin write' ) ) self.assertTrue( b.startswith( 'end write' ) ) self.assertEqual( a[-2:], b[-2:] )