Implement simple test for operation idempotency.
This works by re-executing the same operation call and checking that
the second call outputs no commands (changes). This ensures that
operations correctly update any facts they make use of, and as a result
tests operations will execute exactly as defined by the user.
@@ -65,7 +65,7 @@ def make_operation_tests(arg):
output_commands = unroll_generators(op._pyinfra_op(
*test_data.get('args', []),
**kwargs
- )) or []
+ ))
except Exception as e:
if allowed_exception:
allowed_exception_names = allowed_exception.get('names')
@@ -81,6 +81,16 @@ def make_operation_tests(arg):
raise
+ if test_data.get('idempotent', True):
+ second_output_commands = unroll_generators(op._pyinfra_op(
+ *test_data.get('args', []),
+ **kwargs
+ ))
+ if second_output_commands:
+ raise Exception((
+ 'Operation not idempotent, second output commands: {0}'
+ ).format(second_output_commands))
+
commands = []
for command in output_commands:
