@@ -1469,93 +1469,6 @@ async def run_async_tests():
14691469 # Verify all readers completed
14701470 self .assertEqual (active_readers , 0 , "Not all readers completed" )
14711471
1472- def test_builder_sign_with_multiple_ingredient (self ):
1473- """Test Builder class operations with multiple ingredients added in parallel threads."""
1474- # Test creating builder from JSON
1475- builder = Builder .from_json (self .manifestDefinition )
1476- assert builder ._builder is not None
1477-
1478- # Define paths for test files
1479- cloud_path = os .path .join (self .data_dir , "cloud.jpg" )
1480-
1481- # Thread synchronization
1482- ingredient_added = threading .Event ()
1483- add_errors = []
1484- add_lock = threading .Lock ()
1485-
1486- def add_ingredient (ingredient_json , file_path , thread_id ):
1487- try :
1488- with open (file_path , 'rb' ) as f :
1489- builder .add_ingredient (ingredient_json , "image/jpeg" , f )
1490- with add_lock :
1491- add_errors .append (None ) # Success case
1492- except Exception as e :
1493- with add_lock :
1494- add_errors .append (f"Thread { thread_id } error: { str (e )} " )
1495- finally :
1496- ingredient_added .set ()
1497-
1498- # Create and start two threads for parallel ingredient addition
1499- thread1 = threading .Thread (
1500- target = add_ingredient ,
1501- args = ('{"title": "Test Ingredient 1"}' , self .testPath3 , 1 )
1502- )
1503- thread2 = threading .Thread (
1504- target = add_ingredient ,
1505- args = ('{"title": "Test Ingredient 2"}' , cloud_path , 2 )
1506- )
1507-
1508- # Start both threads
1509- thread1 .start ()
1510- thread2 .start ()
1511-
1512- # Wait for both threads to complete
1513- thread1 .join ()
1514- thread2 .join ()
1515-
1516- # Check for errors during ingredient addition
1517- if any (error for error in add_errors if error is not None ):
1518- self .fail (
1519- "\n " .join (
1520- error for error in add_errors if error is not None ))
1521-
1522- # Verify both ingredients were added successfully
1523- self .assertEqual (
1524- len (add_errors ),
1525- 2 ,
1526- "Both threads should have completed" )
1527-
1528- # Now sign the manifest with the added ingredients
1529- with open (self .testPath2 , "rb" ) as file :
1530- output = io .BytesIO (bytearray ())
1531- builder .sign (self .signer , "image/jpeg" , file , output )
1532- output .seek (0 )
1533- reader = Reader ("image/jpeg" , output )
1534- json_data = reader .json ()
1535- manifest_data = json .loads (json_data )
1536-
1537- # Verify active manifest exists
1538- self .assertIn ("active_manifest" , manifest_data )
1539- active_manifest_id = manifest_data ["active_manifest" ]
1540-
1541- # Verify active manifest object exists
1542- self .assertIn ("manifests" , manifest_data )
1543- self .assertIn (active_manifest_id , manifest_data ["manifests" ])
1544- active_manifest = manifest_data ["manifests" ][active_manifest_id ]
1545-
1546- # Verify ingredients array exists in active manifest
1547- self .assertIn ("ingredients" , active_manifest )
1548- self .assertIsInstance (active_manifest ["ingredients" ], list )
1549- self .assertEqual (len (active_manifest ["ingredients" ]), 2 )
1550-
1551- # Verify both ingredients exist in the array (order doesn't matter)
1552- ingredient_titles = [ing ["title" ]
1553- for ing in active_manifest ["ingredients" ]]
1554- self .assertIn ("Test Ingredient 1" , ingredient_titles )
1555- self .assertIn ("Test Ingredient 2" , ingredient_titles )
1556-
1557- builder .close ()
1558-
15591472 def test_builder_sign_with_multiple_ingredients_from_stream (self ):
15601473 """Test Builder class operations with multiple ingredients using streams."""
15611474 # Test creating builder from JSON
@@ -1648,248 +1561,6 @@ def add_ingredient_from_stream(ingredient_json, file_path, thread_id):
16481561
16491562 builder .close ()
16501563
1651- def test_builder_sign_with_multiple_ingredient_random (self ):
1652- """Test Builder class operations with 5 random ingredients added in parallel threads."""
1653- # Test creating builder from JSON
1654- builder = Builder .from_json (self .manifestDefinition )
1655- assert builder ._builder is not None
1656-
1657- # Get list of files from files-for-reading-tests directory
1658- reading_dir = os .path .join (self .data_dir , "files-for-reading-tests" )
1659- all_files = [
1660- f for f in os .listdir (reading_dir ) if os .path .isfile (
1661- os .path .join (
1662- reading_dir , f ))]
1663-
1664- # Select 5 random files
1665- random .seed (42 ) # For reproducible testing
1666- selected_files = random .sample (all_files , 5 )
1667-
1668- # Thread synchronization
1669- add_errors = []
1670- add_lock = threading .Lock ()
1671- completed_threads = 0
1672- completion_lock = threading .Lock ()
1673-
1674- def add_ingredient (file_name , thread_id ):
1675- nonlocal completed_threads
1676- try :
1677- file_path = os .path .join (reading_dir , file_name )
1678- ingredient_json = json .dumps ({
1679- "title" : f"Test Ingredient Thread { thread_id } - { file_name } "
1680- })
1681-
1682- with open (file_path , 'rb' ) as f :
1683- builder .add_ingredient (ingredient_json , "image/jpeg" , f )
1684-
1685- with add_lock :
1686- add_errors .append (None ) # Success case
1687- except Exception as e :
1688- with add_lock :
1689- add_errors .append (
1690- f"Thread { thread_id } error with file { file_name } : {
1691- str (e )} " )
1692- finally :
1693- with completion_lock :
1694- completed_threads += 1
1695-
1696- # Create and start 5 threads for parallel ingredient addition
1697- threads = []
1698- for i , file_name in enumerate (selected_files , 1 ):
1699- thread = threading .Thread (
1700- target = add_ingredient ,
1701- args = (file_name , i )
1702- )
1703- threads .append (thread )
1704- thread .start ()
1705-
1706- # Wait for all threads to complete
1707- for thread in threads :
1708- thread .join ()
1709-
1710- # Check for errors during ingredient addition
1711- if any (error for error in add_errors if error is not None ):
1712- self .fail (
1713- "\n " .join (
1714- error for error in add_errors if error is not None ))
1715-
1716- # Verify all ingredients were added successfully
1717- self .assertEqual (
1718- completed_threads ,
1719- 5 ,
1720- "All 5 threads should have completed" )
1721- self .assertEqual (
1722- len (add_errors ),
1723- 5 ,
1724- "All 5 threads should have completed without errors" )
1725-
1726- # Now sign the manifest with the added ingredients
1727- with open (self .testPath2 , "rb" ) as file :
1728- output = io .BytesIO (bytearray ())
1729- builder .sign (self .signer , "image/jpeg" , file , output )
1730- output .seek (0 )
1731- reader = Reader ("image/jpeg" , output )
1732- json_data = reader .json ()
1733- manifest_data = json .loads (json_data )
1734-
1735- # Verify active manifest exists
1736- self .assertIn ("active_manifest" , manifest_data )
1737- active_manifest_id = manifest_data ["active_manifest" ]
1738-
1739- # Verify active manifest object exists
1740- self .assertIn ("manifests" , manifest_data )
1741- self .assertIn (active_manifest_id , manifest_data ["manifests" ])
1742- active_manifest = manifest_data ["manifests" ][active_manifest_id ]
1743-
1744- # Verify ingredients array exists in active manifest
1745- self .assertIn ("ingredients" , active_manifest )
1746- self .assertIsInstance (active_manifest ["ingredients" ], list )
1747- self .assertEqual (len (active_manifest ["ingredients" ]), 5 )
1748-
1749- # Verify all ingredients exist in the array with correct thread IDs
1750- ingredient_titles = [ing ["title" ]
1751- for ing in active_manifest ["ingredients" ]]
1752- for i in range (1 , 6 ):
1753- # Find an ingredient with this thread ID
1754- thread_ingredients = [
1755- title for title in ingredient_titles if f"Thread { i } " in title ]
1756- self .assertEqual (
1757- len (thread_ingredients ),
1758- 1 ,
1759- f"Should find exactly one ingredient for thread { i } " )
1760-
1761- # Verify the ingredient title contains the file name
1762- thread_ingredient = thread_ingredients [0 ]
1763- file_name = selected_files [i - 1 ]
1764- self .assertIn (
1765- file_name ,
1766- thread_ingredient ,
1767- f"Ingredient for thread { i } should contain its file name" )
1768-
1769- builder .close ()
1770-
1771- def test_builder_sign_with_multiple_ingredient_async_random (self ):
1772- """Test Builder class operations with 5 random ingredients added in parallel using asyncio."""
1773- # Test creating builder from JSON
1774- builder = Builder .from_json (self .manifestDefinition )
1775- assert builder ._builder is not None
1776-
1777- # Get list of files from files-for-reading-tests directory
1778- reading_dir = os .path .join (self .data_dir , "files-for-reading-tests" )
1779- all_files = [
1780- f for f in os .listdir (reading_dir ) if os .path .isfile (
1781- os .path .join (
1782- reading_dir , f ))]
1783-
1784- # Select 5 random files
1785- random .seed (42 ) # For reproducible testing
1786- selected_files = random .sample (all_files , 5 )
1787-
1788- # Async synchronization
1789- add_errors = []
1790- add_lock = asyncio .Lock ()
1791- completed_tasks = 0
1792- completion_lock = asyncio .Lock ()
1793- # Barrier to synchronize task starts
1794- start_barrier = asyncio .Barrier (5 )
1795-
1796- async def add_ingredient (file_name , task_id ):
1797- nonlocal completed_tasks
1798- try :
1799- # Wait for all tasks to be ready
1800- await start_barrier .wait ()
1801-
1802- file_path = os .path .join (reading_dir , file_name )
1803- ingredient_json = json .dumps ({
1804- "title" : f"Test Ingredient Task { task_id } - { file_name } "
1805- })
1806-
1807- with open (file_path , 'rb' ) as f :
1808- builder .add_ingredient (ingredient_json , "image/jpeg" , f )
1809-
1810- async with add_lock :
1811- add_errors .append (None ) # Success case
1812- except Exception as e :
1813- async with add_lock :
1814- add_errors .append (
1815- f"Task { task_id } error with file { file_name } : {
1816- str (e )} " )
1817- finally :
1818- async with completion_lock :
1819- completed_tasks += 1
1820-
1821- async def run_async_tests ():
1822- # Create all tasks first
1823- tasks = []
1824- for i , file_name in enumerate (selected_files , 1 ):
1825- task = asyncio .create_task (add_ingredient (file_name , i ))
1826- tasks .append (task )
1827-
1828- # Wait for all tasks to complete
1829- await asyncio .gather (* tasks )
1830-
1831- # Check for errors during ingredient addition
1832- if any (error for error in add_errors if error is not None ):
1833- raise Exception (
1834- "\n " .join (
1835- error for error in add_errors if error is not None ))
1836-
1837- # Verify all ingredients were added successfully
1838- self .assertEqual (
1839- completed_tasks ,
1840- 5 ,
1841- "All 5 tasks should have completed" )
1842- self .assertEqual (
1843- len (add_errors ),
1844- 5 ,
1845- "All 5 tasks should have completed without errors" )
1846-
1847- # Now sign the manifest with the added ingredients
1848- with open (self .testPath2 , "rb" ) as file :
1849- output = io .BytesIO (bytearray ())
1850- builder .sign (self .signer , "image/jpeg" , file , output )
1851- output .seek (0 )
1852- reader = Reader ("image/jpeg" , output )
1853- json_data = reader .json ()
1854- manifest_data = json .loads (json_data )
1855-
1856- # Verify active manifest exists
1857- self .assertIn ("active_manifest" , manifest_data )
1858- active_manifest_id = manifest_data ["active_manifest" ]
1859-
1860- # Verify active manifest object exists
1861- self .assertIn ("manifests" , manifest_data )
1862- self .assertIn (active_manifest_id , manifest_data ["manifests" ])
1863- active_manifest = manifest_data ["manifests" ][active_manifest_id ]
1864-
1865- # Verify ingredients array exists in active manifest
1866- self .assertIn ("ingredients" , active_manifest )
1867- self .assertIsInstance (active_manifest ["ingredients" ], list )
1868- self .assertEqual (len (active_manifest ["ingredients" ]), 5 )
1869-
1870- # Verify all ingredients exist in the array with correct task
1871- # IDs
1872- ingredient_titles = [ing ["title" ]
1873- for ing in active_manifest ["ingredients" ]]
1874- for i in range (1 , 6 ):
1875- # Find an ingredient with this task ID
1876- task_ingredients = [
1877- title for title in ingredient_titles if f"Task { i } " in title ]
1878- self .assertEqual (
1879- len (task_ingredients ),
1880- 1 ,
1881- f"Should find exactly one ingredient for task { i } " )
1882-
1883- # Verify the ingredient title contains the file name
1884- task_ingredient = task_ingredients [0 ]
1885- file_name = selected_files [i - 1 ]
1886- self .assertIn (file_name , task_ingredient , f"Ingredient for task {
1887- i } should contain its file name" )
1888-
1889- # Run the async tests
1890- asyncio .run (run_async_tests ())
1891- builder .close ()
1892-
18931564 def test_builder_sign_with_same_ingredient_multiple_times (self ):
18941565 """Test Builder class operations with the same ingredient added multiple times from different threads."""
18951566 # Test creating builder from JSON
0 commit comments