11import os
22import subprocess
3+ import tempfile
34from datetime import datetime , time
45from pathlib import Path
56from unittest .mock import MagicMock , patch
67
78import pytest
9+ from aind_behavior_services import AindBehaviorSessionModel
810from aind_data_transfer_service .models .core import Task
911from requests .exceptions import HTTPError
1012
11- from clabe .data_mapper .aind_data_schema import Session
1213from clabe .data_transfer .aind_watchdog import (
13- CORE_FILES ,
1414 ManifestConfig ,
1515 WatchConfig ,
1616 WatchdogDataTransferService ,
2222
2323@pytest .fixture
2424def source ():
25- return Path ("source_path" )
25+ """Create a temporary directory with test folder structure."""
26+ temp_dir = Path (tempfile .mkdtemp (prefix = "source_path" ))
2627
28+ folders = ["behavior" , "not_a_modality" , "behavior-videos" ]
29+ for folder in folders :
30+ folder_path = temp_dir / folder
31+ folder_path .mkdir (exist_ok = True )
2732
28- @pytest .fixture
29- def ads_session ():
30- """Mock Session for testing create_manifest_config_from_ads_session method."""
31- mock_session = MagicMock (spec = Session )
32- mock_session .experimenter_full_name = ["john.doe" , "jane.smith" ]
33- mock_session .subject_id = "12345"
34- mock_session .session_start_time = datetime (2023 , 1 , 1 , 10 , 0 , 0 )
35-
36- # Mock data streams with modalities
37- mock_modality = MagicMock ()
38- mock_modality .abbreviation = "behavior"
39-
40- mock_data_stream = MagicMock ()
41- mock_session .data_streams = [mock_data_stream ]
42- mock_session .data_streams [0 ].stream_modalities = [mock_modality ]
33+ yield temp_dir
34+ import shutil
4335
44- # Mock aind-data-schema v2 attributes because someone did not care about backward compatibility...
45- mock_session .experimenters = mock_session .experimenter_full_name
46- mock_session .acquisition_start_time = mock_session .session_start_time
47- mock_session .data_streams [0 ].modalities = mock_session .data_streams [0 ].stream_modalities
48- return mock_session
36+ shutil .rmtree (temp_dir , ignore_errors = True )
4937
5038
5139@pytest .fixture
@@ -55,27 +43,34 @@ def settings():
5543 schedule_time = time (hour = 20 ),
5644 project_name = "test_project" ,
5745 platform = "behavior" ,
58- capsule_id = "capsule_id" ,
5946 script = {"script_key" : ["script_value" ]},
6047 s3_bucket = "private" ,
61- mount = "mount_path" ,
6248 force_cloud_sync = True ,
6349 transfer_endpoint = "http://aind-data-transfer-service-dev/api/v2/submit_jobs" ,
6450 )
6551
6652
6753@pytest .fixture
68- def watchdog_service (mock_ui_helper , source , settings , ads_session ):
54+ def mock_session ():
55+ return AindBehaviorSessionModel (
56+ experiment = "mock" ,
57+ subject = "007" ,
58+ experiment_version = "0.0.0" ,
59+ root_path = "mock_path" ,
60+ session_name = "mock_session" ,
61+ )
62+
63+
64+ @pytest .fixture
65+ def watchdog_service (mock_ui_helper , source , settings , mock_session ):
6966 os .environ ["WATCHDOG_EXE" ] = "watchdog.exe"
7067 os .environ ["WATCHDOG_CONFIG" ] = str (TESTS_ASSETS / "watch_config.yml" )
7168
7269 service = WatchdogDataTransferService (
7370 source ,
7471 settings = settings ,
75- aind_data_schema_session = ads_session ,
72+ session = mock_session ,
7673 validate = False ,
77- ui_helper = mock_ui_helper ,
78- session_name = "test_session" ,
7974 )
8075
8176 service ._manifest_config = ManifestConfig (
@@ -112,18 +107,6 @@ def watchdog_service(mock_ui_helper, source, settings, ads_session):
112107
113108
114109class TestWatchdogDataTransferService :
115- def test_initialization (self , watchdog_service , settings ):
116- assert watchdog_service ._settings .destination == settings .destination
117- assert watchdog_service ._settings .project_name == settings .project_name
118- assert watchdog_service ._settings .schedule_time == settings .schedule_time
119- assert watchdog_service ._settings .platform == settings .platform
120- assert watchdog_service ._settings .capsule_id == settings .capsule_id
121- assert watchdog_service ._settings .script == settings .script
122- assert watchdog_service ._settings .s3_bucket == settings .s3_bucket
123- assert watchdog_service ._settings .mount == settings .mount
124- assert watchdog_service ._settings .force_cloud_sync == settings .force_cloud_sync
125- assert watchdog_service ._settings .transfer_endpoint == settings .transfer_endpoint
126-
127110 @patch ("clabe.data_transfer.aind_watchdog.subprocess.check_output" )
128111 def test_is_running (self , mock_check_output , watchdog_service ):
129112 mock_check_output .return_value = (
@@ -180,21 +163,13 @@ def test_validate_fail(self, mock_is_running, watchdog_service):
180163 with pytest .raises (FileNotFoundError ):
181164 watchdog_service .validate ()
182165
183- def test_missing_env_variables (self , source , settings , ads_session ):
166+ def test_missing_env_variables (self , source , settings , mock_session ):
184167 if "WATCHDOG_EXE" in os .environ :
185168 del os .environ ["WATCHDOG_EXE" ]
186169 if "WATCHDOG_CONFIG" in os .environ :
187170 del os .environ ["WATCHDOG_CONFIG" ]
188171 with pytest .raises (ValueError ):
189- WatchdogDataTransferService (source , settings = settings , validate = False , aind_data_schema_session = ads_session )
190-
191- @patch ("clabe.data_transfer.aind_watchdog.Path.exists" , return_value = True )
192- def test_find_ads_schemas (self , mock_exists ):
193- source = "mock_source_path"
194- expected_files = [Path (source ) / f"{ file } .json" for file in CORE_FILES ]
195-
196- result = WatchdogDataTransferService ._find_schema_candidates (Path (source ))
197- assert result == expected_files
172+ WatchdogDataTransferService (source , settings = settings , validate = False , session = mock_session )
198173
199174 @patch ("clabe.data_transfer.aind_watchdog.Path.mkdir" )
200175 @patch ("clabe.data_transfer.aind_watchdog.WatchdogDataTransferService._write_yaml" )
@@ -433,23 +408,6 @@ def test_is_valid_project_name_valid(self, mock_get_project_names, watchdog_serv
433408 def test_is_valid_project_name_invalid (self , mock_get_project_names , watchdog_service ):
434409 assert not watchdog_service .is_valid_project_name ()
435410
436- @patch (
437- "clabe.data_transfer.aind_watchdog.WatchdogDataTransferService._get_project_names" ,
438- return_value = ["other_project" ],
439- )
440- @patch ("clabe.data_transfer.aind_watchdog.WatchdogDataTransferService._find_ads_schemas" , return_value = [])
441- def test_create_manifest_config_from_ads_session_invalid_project_name (
442- self , mock_find_ads_schemas , mock_get_project_names , watchdog_service , ads_session
443- ):
444- watchdog_service ._validate_project_name = True
445- with pytest .raises (ValueError ):
446- watchdog_service ._create_manifest_config_from_ads_session (ads_session )
447-
448-
449- @pytest .fixture
450- def robocopy_source ():
451- return Path ("source_path" )
452-
453411
454412@pytest .fixture
455413def robocopy_settings ():
@@ -464,17 +422,17 @@ def robocopy_settings():
464422
465423
466424@pytest .fixture
467- def robocopy_service (mock_ui_helper , robocopy_source , robocopy_settings ):
425+ def robocopy_service (mock_ui_helper , source , robocopy_settings ):
468426 return RobocopyService (
469- source = robocopy_source ,
427+ source = source ,
470428 settings = robocopy_settings ,
471429 ui_helper = mock_ui_helper ,
472430 )
473431
474432
475433class TestRobocopyService :
476- def test_initialization (self , robocopy_service , robocopy_source , robocopy_settings ):
477- assert robocopy_service .source == robocopy_source
434+ def test_initialization (self , robocopy_service , source , robocopy_settings ):
435+ assert robocopy_service .source == source
478436 assert robocopy_service ._settings .destination == robocopy_settings .destination
479437 assert robocopy_service ._settings .log == robocopy_settings .log
480438 assert robocopy_service ._settings .extra_args == robocopy_settings .extra_args
@@ -490,15 +448,15 @@ def test_transfer(self, mock_ui_helper, robocopy_service):
490448 mock_popen .return_value = mock_process
491449 robocopy_service .transfer ()
492450
493- def test_solve_src_dst_mapping_single_path (self , robocopy_service , robocopy_source , robocopy_settings ):
494- result = robocopy_service ._solve_src_dst_mapping (robocopy_source , robocopy_settings .destination )
495- assert result == {Path (robocopy_source ): Path (robocopy_settings .destination )}
451+ def test_solve_src_dst_mapping_single_path (self , robocopy_service , source , robocopy_settings ):
452+ result = robocopy_service ._solve_src_dst_mapping (source , robocopy_settings .destination )
453+ assert result == {Path (source ): Path (robocopy_settings .destination )}
496454
497- def test_solve_src_dst_mapping_dict (self , robocopy_service , robocopy_source , robocopy_settings ):
498- source_dict = {robocopy_source : robocopy_settings .destination }
455+ def test_solve_src_dst_mapping_dict (self , robocopy_service , source , robocopy_settings ):
456+ source_dict = {source : robocopy_settings .destination }
499457 result = robocopy_service ._solve_src_dst_mapping (source_dict , None )
500458 assert result == source_dict
501459
502- def test_solve_src_dst_mapping_invalid (self , robocopy_service , robocopy_source ):
460+ def test_solve_src_dst_mapping_invalid (self , robocopy_service , source ):
503461 with pytest .raises (ValueError ):
504- robocopy_service ._solve_src_dst_mapping (robocopy_source , None )
462+ robocopy_service ._solve_src_dst_mapping (source , None )
0 commit comments