77from contextlib import asynccontextmanager
88from pathlib import Path
99from random import choice , randint
10- from typing import Any
10+ from typing import Any , cast
1111
1212import pytest
1313import sqlalchemy as sa
1414from faker import Faker
1515from models_library .basic_types import SHA256Str
1616from models_library .projects import ProjectID
17- from models_library .projects_nodes_io import NodeID , SimcoreS3FileID
17+ from models_library .projects_nodes_io import NodeID , SimcoreS3FileID , StorageFileID
1818from models_library .users import UserID
1919from pydantic import ByteSize , TypeAdapter
20- from pytest_simcore .helpers .faker_factories import random_project , random_user
2120from servicelib .utils import limited_gather
2221from simcore_postgres_database .models .project_to_groups import project_to_groups
2322from simcore_postgres_database .storage_models import projects , users
2423from sqlalchemy .dialects .postgresql import insert as pg_insert
2524from sqlalchemy .ext .asyncio import AsyncConnection , AsyncEngine
2625
27- from ..helpers .utils import get_updated_project
26+ from .helpers .faker_factories import random_project , random_user
27+ from .helpers .storage_utils import FileIDDict , get_updated_project
2828
2929
3030@asynccontextmanager
@@ -259,6 +259,39 @@ async def _creator(
259259 return _creator
260260
261261
262+ async def _upload_file_and_update_project (
263+ project_id : ProjectID ,
264+ node_id : NodeID ,
265+ * ,
266+ file_name : str | None ,
267+ file_id : StorageFileID | None ,
268+ file_sizes : tuple [ByteSize , ...],
269+ file_checksums : tuple [SHA256Str , ...],
270+ node_to_files_mapping : dict [NodeID , dict [SimcoreS3FileID , FileIDDict ]],
271+ upload_file : Callable [..., Awaitable [tuple [Path , SimcoreS3FileID ]]],
272+ create_simcore_file_id : Callable [
273+ [ProjectID , NodeID , str , Path | None ], SimcoreS3FileID
274+ ],
275+ faker : Faker ,
276+ ) -> None :
277+ if file_name is None :
278+ file_name = faker .file_name ()
279+ file_id = create_simcore_file_id (project_id , node_id , file_name , None )
280+ checksum : SHA256Str = choice (file_checksums ) # noqa: S311
281+ src_file , _ = await upload_file (
282+ file_size = choice (file_sizes ), # noqa: S311
283+ file_name = file_name ,
284+ file_id = file_id ,
285+ sha256_checksum = checksum ,
286+ )
287+ assert file_name is not None
288+ assert file_id is not None
289+ node_to_files_mapping [node_id ][file_id ] = {
290+ "path" : src_file ,
291+ "sha256_checksum" : checksum ,
292+ }
293+
294+
262295@pytest .fixture
263296async def random_project_with_files (
264297 sqlalchemy_async_engine : AsyncEngine ,
@@ -271,11 +304,7 @@ async def random_project_with_files(
271304 faker : Faker ,
272305) -> Callable [
273306 [int , tuple [ByteSize , ...], tuple [SHA256Str , ...]],
274- Awaitable [
275- tuple [
276- dict [str , Any ], dict [NodeID , dict [SimcoreS3FileID , dict [str , Path | str ]]]
277- ]
278- ],
307+ Awaitable [tuple [dict [str , Any ], dict [NodeID , dict [SimcoreS3FileID , FileIDDict ]]]],
279308]:
280309 async def _creator (
281310 num_nodes : int = 12 ,
@@ -295,76 +324,67 @@ async def _creator(
295324 "488f3b57932803bbf644593bd46d95599b1d4da1d63bc020d7ebe6f1c255f7f3"
296325 ),
297326 ),
298- ) -> tuple [
299- dict [str , Any ], dict [NodeID , dict [SimcoreS3FileID , dict [str , Path | str ]]]
300- ]:
327+ ) -> tuple [dict [str , Any ], dict [NodeID , dict [SimcoreS3FileID , FileIDDict ]]]:
301328 assert len (file_sizes ) == len (file_checksums )
302329 project = await create_project (name = "random-project" )
303- src_projects_list : dict [
304- NodeID , dict [SimcoreS3FileID , dict [str , Path | str ]]
305- ] = {}
330+ node_to_files_mapping : dict [NodeID , dict [SimcoreS3FileID , FileIDDict ]] = {}
306331 upload_tasks : deque [Awaitable ] = deque ()
307332 for _node_index in range (num_nodes ):
308- # NOTE: we put some more outputs in there to simulate a real case better
309- new_node_id = NodeID (f"{ faker .uuid4 ()} " )
333+ # Create a node with outputs (files and others)
334+ project_id = ProjectID (project ["uuid" ])
335+ node_id = cast (NodeID , faker .uuid4 (cast_to = None ))
336+ output3_file_name = faker .file_name ()
310337 output3_file_id = create_simcore_file_id (
311- ProjectID (project ["uuid" ]),
312- new_node_id ,
313- faker .file_name (),
314- Path ("outputs/output3" ),
338+ project_id , node_id , output3_file_name , Path ("outputs/output_3" )
315339 )
316- src_node_id = await create_project_node (
340+ created_node_id = await create_project_node (
317341 ProjectID (project ["uuid" ]),
318- new_node_id ,
342+ node_id ,
319343 outputs = {
320344 "output_1" : faker .pyint (),
321345 "output_2" : faker .pystr (),
322346 "output_3" : f"{ output3_file_id } " ,
323347 },
324348 )
325- assert src_node_id == new_node_id
326-
327- # upload the output 3 and some random other files at the root of each node
328- src_projects_list [src_node_id ] = {}
329- checksum : SHA256Str = choice (file_checksums ) # noqa: S311
330- src_file , _ = await upload_file (
331- file_size = choice (file_sizes ), # noqa: S311
332- file_name = Path (output3_file_id ).name ,
333- file_id = output3_file_id ,
334- sha256_checksum = checksum ,
335- )
336- src_projects_list [src_node_id ][output3_file_id ] = {
337- "path" : src_file ,
338- "sha256_checksum" : checksum ,
339- }
340-
341- async def _upload_file_and_update_project (project , src_node_id ):
342- src_file_name = faker .file_name ()
343- src_file_uuid = create_simcore_file_id (
344- ProjectID (project ["uuid" ]), src_node_id , src_file_name , None
345- )
346- checksum : SHA256Str = choice (file_checksums ) # noqa: S311
347- src_file , _ = await upload_file (
348- file_size = choice (file_sizes ), # noqa: S311
349- file_name = src_file_name ,
350- file_id = src_file_uuid ,
351- sha256_checksum = checksum ,
349+ assert created_node_id == node_id
350+
351+ node_to_files_mapping [created_node_id ] = {}
352+ upload_tasks .append (
353+ _upload_file_and_update_project (
354+ project_id ,
355+ node_id ,
356+ file_name = output3_file_name ,
357+ file_id = output3_file_id ,
358+ file_sizes = file_sizes ,
359+ file_checksums = file_checksums ,
360+ upload_file = upload_file ,
361+ create_simcore_file_id = create_simcore_file_id ,
362+ faker = faker ,
363+ node_to_files_mapping = node_to_files_mapping ,
352364 )
353- src_projects_list [src_node_id ][src_file_uuid ] = {
354- "path" : src_file ,
355- "sha256_checksum" : checksum ,
356- }
365+ )
357366
358- # add a few random files in the node storage
367+ # add a few random files in the node workspace
359368 upload_tasks .extend (
360369 [
361- _upload_file_and_update_project (project , src_node_id )
370+ _upload_file_and_update_project (
371+ project_id ,
372+ node_id ,
373+ file_name = None ,
374+ file_id = None ,
375+ file_sizes = file_sizes ,
376+ file_checksums = file_checksums ,
377+ upload_file = upload_file ,
378+ create_simcore_file_id = create_simcore_file_id ,
379+ faker = faker ,
380+ node_to_files_mapping = node_to_files_mapping ,
381+ )
362382 for _ in range (randint (0 , 3 )) # noqa: S311
363383 ]
364384 )
365385 await limited_gather (* upload_tasks , limit = 10 )
366386
367387 project = await get_updated_project (sqlalchemy_async_engine , project ["uuid" ])
368- return project , src_projects_list
388+ return project , node_to_files_mapping
369389
370390 return _creator
0 commit comments