spaceforge 0.1.0.dev0__py3-none-any.whl → 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spaceforge/__init__.py +12 -4
- spaceforge/__main__.py +3 -3
- spaceforge/_version.py +0 -1
- spaceforge/_version_scm.py +34 -0
- spaceforge/cls.py +24 -14
- spaceforge/conftest.py +89 -0
- spaceforge/generator.py +129 -56
- spaceforge/plugin.py +199 -22
- spaceforge/runner.py +3 -15
- spaceforge/schema.json +45 -22
- spaceforge/templates/binary_install.sh.j2 +24 -0
- spaceforge/templates/ensure_spaceforge_and_run.sh.j2 +24 -0
- spaceforge/{generator_test.py → test_generator.py} +265 -53
- spaceforge/test_generator_binaries.py +194 -0
- spaceforge/test_generator_core.py +180 -0
- spaceforge/test_generator_hooks.py +90 -0
- spaceforge/test_generator_parameters.py +59 -0
- spaceforge/test_plugin.py +357 -0
- spaceforge/test_plugin_file_operations.py +118 -0
- spaceforge/test_plugin_hooks.py +100 -0
- spaceforge/test_plugin_inheritance.py +102 -0
- spaceforge/{runner_test.py → test_runner.py} +5 -68
- spaceforge/test_runner_cli.py +69 -0
- spaceforge/test_runner_core.py +124 -0
- spaceforge/test_runner_execution.py +169 -0
- spaceforge-1.0.1.dist-info/METADATA +606 -0
- spaceforge-1.0.1.dist-info/RECORD +33 -0
- spaceforge/plugin_test.py +0 -621
- spaceforge-0.1.0.dev0.dist-info/METADATA +0 -163
- spaceforge-0.1.0.dev0.dist-info/RECORD +0 -19
- /spaceforge/{cls_test.py → test_cls.py} +0 -0
- {spaceforge-0.1.0.dev0.dist-info → spaceforge-1.0.1.dist-info}/WHEEL +0 -0
- {spaceforge-0.1.0.dev0.dist-info → spaceforge-1.0.1.dist-info}/entry_points.txt +0 -0
- {spaceforge-0.1.0.dev0.dist-info → spaceforge-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {spaceforge-0.1.0.dev0.dist-info → spaceforge-1.0.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""Tests for PluginRunner hook execution functionality."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from unittest.mock import Mock, patch
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from spaceforge.runner import PluginRunner
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestPluginRunnerExecution:
|
|
12
|
+
"""Test hook execution functionality."""
|
|
13
|
+
|
|
14
|
+
def test_should_load_plugin_automatically_when_not_already_loaded(
|
|
15
|
+
self, test_plugin_file: str
|
|
16
|
+
) -> None:
|
|
17
|
+
"""Should call load_plugin when plugin_instance is None."""
|
|
18
|
+
# Arrange
|
|
19
|
+
runner = PluginRunner(test_plugin_file)
|
|
20
|
+
|
|
21
|
+
# Act
|
|
22
|
+
with patch.object(runner, "load_plugin") as mock_load:
|
|
23
|
+
mock_instance = Mock()
|
|
24
|
+
mock_instance.after_plan = Mock()
|
|
25
|
+
runner.plugin_instance = None
|
|
26
|
+
runner.run_hook("after_plan")
|
|
27
|
+
|
|
28
|
+
# Assert
|
|
29
|
+
mock_load.assert_called_once()
|
|
30
|
+
|
|
31
|
+
def test_should_execute_hook_and_log_success_when_hook_exists(
|
|
32
|
+
self, temp_dir: str
|
|
33
|
+
) -> None:
|
|
34
|
+
"""Should successfully execute hook method and log completion."""
|
|
35
|
+
# Arrange
|
|
36
|
+
runner_plugin_path = os.path.join(temp_dir, "runner_plugin.py")
|
|
37
|
+
with open(runner_plugin_path, "w") as f:
|
|
38
|
+
f.write(
|
|
39
|
+
"""
|
|
40
|
+
from spaceforge import SpaceforgePlugin
|
|
41
|
+
|
|
42
|
+
class TestRunnerPlugin(SpaceforgePlugin):
|
|
43
|
+
def __init__(self):
|
|
44
|
+
super().__init__()
|
|
45
|
+
self.executed_hooks = []
|
|
46
|
+
|
|
47
|
+
def after_plan(self):
|
|
48
|
+
self.executed_hooks.append('after_plan')
|
|
49
|
+
"""
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
runner = PluginRunner(runner_plugin_path)
|
|
53
|
+
runner.load_plugin()
|
|
54
|
+
|
|
55
|
+
# Act
|
|
56
|
+
with patch("builtins.print") as mock_print:
|
|
57
|
+
runner.run_hook("after_plan")
|
|
58
|
+
|
|
59
|
+
# Assert
|
|
60
|
+
assert runner.plugin_instance is not None
|
|
61
|
+
assert hasattr(runner.plugin_instance, "executed_hooks")
|
|
62
|
+
assert "after_plan" in getattr(runner.plugin_instance, "executed_hooks")
|
|
63
|
+
|
|
64
|
+
mock_print.assert_any_call("[SpaceForge] Running hook: after_plan")
|
|
65
|
+
mock_print.assert_any_call("[SpaceForge] Hook completed: after_plan")
|
|
66
|
+
|
|
67
|
+
def test_should_print_error_when_hook_method_not_found(
|
|
68
|
+
self, test_plugin_file: str
|
|
69
|
+
) -> None:
|
|
70
|
+
"""Should print error message when hook method doesn't exist."""
|
|
71
|
+
# Arrange
|
|
72
|
+
runner = PluginRunner(test_plugin_file)
|
|
73
|
+
runner.load_plugin()
|
|
74
|
+
|
|
75
|
+
# Act
|
|
76
|
+
with patch("builtins.print") as mock_print:
|
|
77
|
+
runner.run_hook("nonexistent_hook")
|
|
78
|
+
|
|
79
|
+
# Assert
|
|
80
|
+
mock_print.assert_called_with(
|
|
81
|
+
"Hook method 'nonexistent_hook' not found in plugin"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
def test_should_print_error_when_hook_exists_but_not_callable(
|
|
85
|
+
self, test_plugin_file: str
|
|
86
|
+
) -> None:
|
|
87
|
+
"""Should print error when hook attribute exists but is not callable."""
|
|
88
|
+
# Arrange
|
|
89
|
+
runner = PluginRunner(test_plugin_file)
|
|
90
|
+
runner.load_plugin()
|
|
91
|
+
|
|
92
|
+
assert runner.plugin_instance is not None
|
|
93
|
+
setattr(runner.plugin_instance, "not_callable", "not a method")
|
|
94
|
+
|
|
95
|
+
# Act
|
|
96
|
+
with patch("builtins.print") as mock_print:
|
|
97
|
+
runner.run_hook("not_callable")
|
|
98
|
+
|
|
99
|
+
# Assert
|
|
100
|
+
mock_print.assert_called_with("'not_callable' is not a callable method")
|
|
101
|
+
|
|
102
|
+
def test_should_print_error_and_reraise_when_hook_execution_fails(
|
|
103
|
+
self, temp_dir: str
|
|
104
|
+
) -> None:
|
|
105
|
+
"""Should print error and re-raise exception when hook execution fails."""
|
|
106
|
+
# Arrange
|
|
107
|
+
error_plugin_path = os.path.join(temp_dir, "error_plugin.py")
|
|
108
|
+
with open(error_plugin_path, "w") as f:
|
|
109
|
+
f.write(
|
|
110
|
+
"""
|
|
111
|
+
from spaceforge import SpaceforgePlugin
|
|
112
|
+
|
|
113
|
+
class ErrorPlugin(SpaceforgePlugin):
|
|
114
|
+
def error_hook(self):
|
|
115
|
+
raise ValueError("Test error from hook")
|
|
116
|
+
"""
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
runner = PluginRunner(error_plugin_path)
|
|
120
|
+
runner.load_plugin()
|
|
121
|
+
|
|
122
|
+
# Act & Assert
|
|
123
|
+
with patch("builtins.print") as mock_print:
|
|
124
|
+
with pytest.raises(ValueError, match="Test error from hook"):
|
|
125
|
+
runner.run_hook("error_hook")
|
|
126
|
+
|
|
127
|
+
mock_print.assert_any_call(
|
|
128
|
+
"[SpaceForge] Error running hook 'error_hook': Test error from hook"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
def test_should_execute_multiple_hooks_maintaining_state(
|
|
132
|
+
self, temp_dir: str
|
|
133
|
+
) -> None:
|
|
134
|
+
"""Should execute multiple hooks while maintaining plugin instance state."""
|
|
135
|
+
# Arrange
|
|
136
|
+
multi_hook_path = os.path.join(temp_dir, "multi_hook.py")
|
|
137
|
+
with open(multi_hook_path, "w") as f:
|
|
138
|
+
f.write(
|
|
139
|
+
"""
|
|
140
|
+
from spaceforge import SpaceforgePlugin
|
|
141
|
+
|
|
142
|
+
class MultiHookPlugin(SpaceforgePlugin):
|
|
143
|
+
def __init__(self):
|
|
144
|
+
super().__init__()
|
|
145
|
+
self.executed_hooks = []
|
|
146
|
+
|
|
147
|
+
def after_plan(self):
|
|
148
|
+
self.executed_hooks.append('after_plan')
|
|
149
|
+
|
|
150
|
+
def before_apply(self):
|
|
151
|
+
self.executed_hooks.append('before_apply')
|
|
152
|
+
"""
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
runner = PluginRunner(multi_hook_path)
|
|
156
|
+
runner.load_plugin()
|
|
157
|
+
|
|
158
|
+
# Act
|
|
159
|
+
with patch("builtins.print"):
|
|
160
|
+
runner.run_hook("after_plan")
|
|
161
|
+
runner.run_hook("before_apply")
|
|
162
|
+
|
|
163
|
+
# Assert
|
|
164
|
+
assert runner.plugin_instance is not None
|
|
165
|
+
assert hasattr(runner.plugin_instance, "executed_hooks")
|
|
166
|
+
executed = getattr(runner.plugin_instance, "executed_hooks")
|
|
167
|
+
assert "after_plan" in executed
|
|
168
|
+
assert "before_apply" in executed
|
|
169
|
+
assert len(executed) == 2
|