6.6 KiB
Plan for Autotest GUI Mode Implementation
I. Objective:
Create an autotest.py script that can launch the Asset Processor GUI headlessly, load a predefined asset (.zip), select a predefined preset, verify the predicted rule structure against an expected JSON, trigger processing to a predefined output directory, check the output, and analyze logs for errors or specific messages. This serves as a sanity check for core GUI-driven workflows.
II. TestFiles Directory:
A new directory named TestFiles will be created in the project root (c:/Users/Theis/Assetprocessor/Asset-Frameworker/TestFiles/). This directory will house:
- Sample asset
.zipfiles for testing (e.g.,TestFiles/SampleAsset1.zip). - Expected rule structure JSON files (e.g.,
TestFiles/SampleAsset1_PresetX_expected_rules.json). - A subdirectory for test outputs (e.g.,
TestFiles/TestOutputs/).
III. autotest.py Script:
- Location:
c:/Users/Theis/Assetprocessor/Asset-Frameworker/autotest.py(orscripts/autotest.py). - Command-Line Arguments (with defaults pointing to
TestFiles/):--zipfile: Path to the test asset. Default:TestFiles/default_test_asset.zip.--preset: Name of the preset. Default:DefaultTestPreset.--expectedrules: Path to expected rules JSON. Default:TestFiles/default_test_asset_rules.json.--outputdir: Path for processing output. Default:TestFiles/TestOutputs/DefaultTestOutput.--search(optional): Log search term. Default:None.--additional-lines(optional): Context lines for log search. Default:0.
- Core Structure:
- Imports necessary modules from the main application and PySide6.
- Adds project root to
sys.pathfor imports. AutoTesterclass:__init__(self, app_instance: App):- Stores
app_instanceandmain_window. - Initializes
QEventLoop. - Connects
app_instance.all_tasks_finishedtoself._on_all_tasks_finished. - Loads expected rules from the
--expectedrulesfile.
- Stores
run_test(self): Orchestrates the test steps sequentially:- Load ZIP (
main_window.add_input_paths()). - Select Preset (
main_window.preset_editor_widget.editor_preset_list.setCurrentItem()). - Await Prediction (using
QTimerto pollmain_window._pending_predictions, manage withQEventLoop). - Retrieve & Compare Rulelist:
- Get actual rules:
main_window.unified_model.get_all_source_rules(). - Convert actual rules to comparable dict (
_convert_rules_to_comparable()). - Compare with loaded expected rules (
_compare_rules()). If mismatch, log and fail.
- Get actual rules:
- Start Processing (emit
main_window.start_backend_processingwith rules and output settings). - Await Processing (use
QEventLoopwaiting for_on_all_tasks_finished). - Check Output Path (verify existence of output dir, list contents, basic sanity checks like non-emptiness or presence of key asset folders).
- Retrieve & Analyze Logs (
main_window.log_console.log_console_output.toPlainText(), filter by--search, check for tracebacks). - Report result and call
cleanup_and_exit().
- Load ZIP (
_check_prediction_status(self): Slot for prediction polling timer._on_all_tasks_finished(self, processed_count, skipped_count, failed_count): Slot forApp.all_tasks_finishedsignal._convert_rules_to_comparable(self, source_rules_list: List[SourceRule]) -> dict: ConvertsSourceRuleobjects to the JSON structure defined below._compare_rules(self, actual_rules_data: dict, expected_rules_data: dict) -> bool: Implements Option 1 comparison logic:- Errors if an expected field is missing or its value mismatches.
- Logs (but doesn't error on) fields present in actual but not in expected.
_process_and_display_logs(self, logs_text: str): Handles log filtering/display.cleanup_and_exit(self, success=True): QuitsQCoreApplicationandsys.exit().
main()function:- Parses CLI arguments.
- Initializes
QApplication. - Instantiates
main.App()(does not show the GUI). - Instantiates
AutoTester(app_instance). - Uses
QTimer.singleShot(0, tester.run_test)to start the test. - Runs
q_app.exec().
IV. expected_rules.json Structure (Revised):
Located in TestFiles/. Example: TestFiles/SampleAsset1_PresetX_expected_rules.json.
{
"source_rules": [
{
"input_path": "SampleAsset1.zip",
"supplier_identifier": "ExpectedSupplier",
"preset_name": "PresetX",
"assets": [
{
"asset_name": "AssetNameFromPrediction",
"asset_type": "Prop",
"files": [
{
"file_path": "relative/path/to/file1.png",
"item_type": "MAP_COL",
"target_asset_name_override": null
}
]
}
]
}
]
}
V. Mermaid Diagram of Autotest Flow:
graph TD
A[Start autotest.py with CLI Args (defaults to TestFiles/)] --> B{Setup Args & Logging};
B --> C[Init QApplication & main.App (GUI Headless)];
C --> D[Instantiate AutoTester(app_instance)];
D --> E[QTimer.singleShot -> AutoTester.run_test()];
subgraph AutoTester.run_test()
E --> F[Load Expected Rules from --expectedrules JSON];
F --> G[Load ZIP (--zipfile) via main_window.add_input_paths()];
G --> H[Select Preset (--preset) via main_window.preset_editor_widget];
H --> I[Await Prediction (Poll main_window._pending_predictions via QTimer & QEventLoop)];
I -- Prediction Done --> J[Get Actual Rules from main_window.unified_model];
J --> K[Convert Actual Rules to Comparable JSON Structure];
K --> L{Compare Actual vs Expected Rules (Option 1 Logic)};
L -- Match --> M[Start Processing (Emit main_window.start_backend_processing with --outputdir)];
L -- Mismatch --> ZFAIL[Log Mismatch & Call cleanup_and_exit(False)];
M --> N[Await Processing (QEventLoop for App.all_tasks_finished signal)];
N -- Processing Done --> O[Check Output Dir (--outputdir): Exists? Not Empty? Key Asset Folders?];
O --> P[Retrieve & Analyze Logs (Search, Tracebacks)];
P --> Q[Log Test Success & Call cleanup_and_exit(True)];
end
ZFAIL --> ZEND[AutoTester.cleanup_and_exit() -> QCoreApplication.quit() & sys.exit()];
Q --> ZEND;