Summary
mock_module_tracker.py only implements v2_runner_on_ok and v2_runner_on_failed. It does not implement v2_runner_item_on_ok or v2_runner_item_on_failed. As a result, a task with loop: over N items is recorded as exactly 1 call, not N, making per-iteration call count assertions impossible.
Affected file
ansible_playtest/ansible_callback/mock_module_tracker.py
def v2_runner_on_ok(self, result): ...
def v2_runner_on_failed(self, result, ignore_errors=False): ...
# v2_runner_item_on_ok ← missing
# v2_runner_item_on_failed ← missing
Reproducer
Playbook task:
- name: Create projects
my_namespace.my_collection.create_project:
name: "{{ item.name }}"
loop: "{{ projects }}" # projects has 3 items
Scenario assertion:
expected_calls:
my_namespace.my_collection.create_project: 3 # ← always fails; actual count = 1
Expected behaviour
Each loop iteration should increment the call counter, so expected_calls can assert per-item invocations.
Suggested fix
Implement v2_runner_item_on_ok and v2_runner_item_on_failed in MockModuleTracker to record per-item calls.
Workaround
Accept expected_calls: 1 for looped tasks. For true per-item call assertion, move the module call into an included task file and use loop: on ansible.builtin.include_tasks — each include fires v2_runner_on_ok separately.
Summary
mock_module_tracker.pyonly implementsv2_runner_on_okandv2_runner_on_failed. It does not implementv2_runner_item_on_okorv2_runner_item_on_failed. As a result, a task withloop:over N items is recorded as exactly 1 call, not N, making per-iteration call count assertions impossible.Affected file
ansible_playtest/ansible_callback/mock_module_tracker.pyReproducer
Playbook task:
Scenario assertion:
Expected behaviour
Each loop iteration should increment the call counter, so
expected_callscan assert per-item invocations.Suggested fix
Implement
v2_runner_item_on_okandv2_runner_item_on_failedinMockModuleTrackerto record per-item calls.Workaround
Accept
expected_calls: 1for looped tasks. For true per-item call assertion, move the module call into an included task file and useloop:onansible.builtin.include_tasks— each include firesv2_runner_on_okseparately.