From c5f37f6bd63072a672616d680845e2f77aa00066 Mon Sep 17 00:00:00 2001
From: Pilou <pierre-louis@libregerbil.fr>
Date: Wed, 8 Aug 2018 06:48:03 +0200
Subject: [PATCH] improve 'service' integration tests (#43655)

* service tests: check that daemon is really running

(spoiler: it isn't)

* service tests: add PIDFile directive in systemd unit

* service tests: check 'changed' too

* service tests: fix indentation & use changed test

* service tests: #16694 has been fixed a long time ago

* service tests: refactor

- always execute cleaning tasks
- move tests tasks in a dedicated file

* service tests: add test for #42786

* service tests: display value of ansible_service_mgr

* service tests: allow to run tests twice in a row

stop & disable ansible test service

* service tests: 'pattern' value must be a substring

'pattern' parameter is poorly named

* service tests: check ansible_test service status

* service tests: test daemon must handle SIGHUP

because 'initctl reload' sends SIGHUP, otherwise test daemon stops when
receiving the signal

* service tests: remove upstart override file too

and check that files were removed using raw module and stat command
---
 .../targets/service/files/ansible.systemd     |   1 +
 .../service/files/ansible_test_service        |   3 +
 .../targets/service/tasks/main.yml            | 184 ++++--------------
 .../targets/service/tasks/systemd_setup.yml   |   2 +-
 .../targets/service/tasks/tests.yml           | 164 ++++++++++++++++
 .../targets/service/tasks/upstart_cleanup.yml |  30 +--
 6 files changed, 225 insertions(+), 159 deletions(-)
 create mode 100644 test/integration/targets/service/tasks/tests.yml

diff --git a/test/integration/targets/service/files/ansible.systemd b/test/integration/targets/service/files/ansible.systemd
index c1a710a1b3e..3466f25a08f 100644
--- a/test/integration/targets/service/files/ansible.systemd
+++ b/test/integration/targets/service/files/ansible.systemd
@@ -5,6 +5,7 @@ Description=Ansible Test Service
 ExecStart=/usr/sbin/ansible_test_service "Test\nthat newlines in scripts\nwork"
 ExecReload=/bin/true
 Type=forking
+PIDFile=/var/run/ansible_test_service.pid
 
 [Install]
 WantedBy=multi-user.target
diff --git a/test/integration/targets/service/files/ansible_test_service b/test/integration/targets/service/files/ansible_test_service
index 682edebb85b..598bc1a4c93 100755
--- a/test/integration/targets/service/files/ansible_test_service
+++ b/test/integration/targets/service/files/ansible_test_service
@@ -5,6 +5,7 @@
 
 import os
 import resource
+import signal
 import sys
 import time
 
@@ -60,6 +61,8 @@ def createDaemon():
 
 if __name__ == "__main__":
 
+   signal.signal(signal.SIGHUP, signal.SIG_IGN)
+
    retCode = createDaemon()
 
    while True:
diff --git a/test/integration/targets/service/tasks/main.yml b/test/integration/targets/service/tasks/main.yml
index 5d327043eb6..a131bf9a979 100644
--- a/test/integration/targets/service/tasks/main.yml
+++ b/test/integration/targets/service/tasks/main.yml
@@ -2,153 +2,49 @@
   copy: src=ansible_test_service dest=/usr/sbin/ansible_test_service mode=755
   register: install_result
 
-- name: assert that the daemon script was installed
-  assert:
-    that:
-    - "install_result.dest == '/usr/sbin/ansible_test_service'"
-    - "install_result.state == 'file'"
-    - "install_result.mode == '0755'"
+- block:
+    - name: assert that the daemon script was installed
+      assert:
+        that:
+          - "install_result.dest == '/usr/sbin/ansible_test_service'"
+          - "install_result.state == 'file'"
+          - "install_result.mode == '0755'"
 
-# determine init system is in use
-- name: detect sysv init system
-  set_fact: service_type=sysv
-  when: ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux'] and ( ansible_distribution_version is version('6', '>=') and ansible_distribution_version is version('7', '<'))
-- name: detect systemd init system
-  set_fact: service_type=systemd
-  when: (ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux'] and ( ansible_distribution_version is version('7', '>=') and ansible_distribution_version is version('8', '<'))) or ansible_distribution == 'Fedora' or (ansible_distribution == 'Ubuntu' and ansible_distribution_version is version('15.04', '>=')) or (ansible_distribution == 'Debian' and ansible_distribution_version is version('8', '>=')) or ansible_os_family == 'Suse'
-- name: detect upstart init system
-  set_fact: service_type=upstart
-  when: ansible_distribution == 'Ubuntu' and ansible_distribution_version is version('15.04', '<')
+    # determine init system is in use
+    - name: detect sysv init system
+      set_fact:
+        service_type: sysv
+      when:
+        - ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux']
+        - ansible_distribution_version is version('6', '>=')
+        - ansible_distribution_version is version('7', '<')
+    - name: detect systemd init system
+      set_fact:
+        service_type: systemd
+      when: (ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux'] and ( ansible_distribution_version is version('7', '>=') and ansible_distribution_version is version('8', '<'))) or ansible_distribution == 'Fedora' or (ansible_distribution == 'Ubuntu' and ansible_distribution_version is version('15.04', '>=')) or (ansible_distribution == 'Debian' and ansible_distribution_version is version('8', '>=')) or ansible_os_family == 'Suse'
+    - name: detect upstart init system
+      set_fact:
+        service_type: upstart
+      when:
+        - ansible_distribution == 'Ubuntu'
+        - ansible_distribution_version is version('15.04', '<')
 
-# setup test service script
-- include: 'sysv_setup.yml'
-  when: service_type == "sysv"
-- include: 'systemd_setup.yml'
-  when: service_type == "systemd"
-- include: 'upstart_setup.yml'
-  when: service_type == "upstart"
+    - name: display value of ansible_service_mgr
+      debug:
+        msg: 'ansible_service_mgr: {{ ansible_service_mgr }}'
 
-- name: disable the ansible test service
-  service: name=ansible_test enabled=no
+    - name: setup test service script
+      include_tasks: '{{ service_type }}_setup.yml'
 
-- name: (check mode run) enable the ansible test service
-  service: name=ansible_test enabled=yes
-  register: enable_in_check_mode_result
-  check_mode: yes
+    - name: execute tests
+      import_tasks: tests.yml
 
-- name: assert that changes reported for check mode run
-  assert:
-    that:
-    - "enable_in_check_mode_result.changed == true"
+  always:
+    - name: disable and stop ansible test service
+      service:
+        name: ansible_test
+        state: stopped
+        enabled: false
 
-- name: enable the ansible test service
-  service: name=ansible_test enabled=yes
-  register: enable_result
-
-- name: assert that the service was enabled and changes reported
-  assert:
-    that:
-    - "enable_result.enabled == true"
-    - "enable_result.changed == true"
-
-- name: start the ansible test service
-  service: name=ansible_test state=started
-  register: start_result
-
-- name: assert that the service was started
-  assert:
-    that:
-    - "start_result.state == 'started'"
-
-- name: find the service with a pattern
-  service: name=ansible_test pattern="ansible_test_ser*" state=started
-  register: start2_result
-  # don't enable this check yet on systems with systemd because of https://github.com/ansible/ansible/issues/16694
-  when: service_type != "systemd"
-
-- name: assert that the service was started via the pattern
-  assert:
-    that:
-    - "start2_result.name == 'ansible_test'"
-    - "start2_result.state == 'started'"
-  when: service_type != "systemd"
-
-- name: restart the ansible test service
-  service: name=ansible_test state=restarted
-  register: restart_result
-
-- name: assert that the service was restarted
-  assert:
-    that:
-    - "restart_result.state == 'started'"
-
-- name: restart the ansible test service with a sleep
-  service: name=ansible_test state=restarted sleep=2
-  register: restart_sleep_result
-  # don't enable this check yet on systems with systemd because of https://github.com/ansible/ansible/issues/16694
-  when: service_type != "systemd"
-
-- name: assert that the service was restarted with a sleep
-  assert:
-    that:
-    - "restart_sleep_result.state == 'started'"
-  when: service_type != "systemd"
-
-- name: reload the ansible test service
-  service: name=ansible_test state=reloaded
-  register: reload_result
-  # don't do this on systems with systemd because it triggers error:
-  #   Unable to reload service ansible_test: ansible_test.service is not active, cannot reload.
-  when: service_type != "systemd"
-
-- name: assert that the service was reloaded
-  assert:
-    that:
-    - "reload_result.state == 'started'"
-  when: service_type != "systemd"
-
-- name: stop the ansible test service
-  service: name=ansible_test state=stopped
-  register: stop_result
-
-- name: assert that the service was stopped
-  assert:
-    that:
-    - "stop_result.state == 'stopped'"
-
-- name: disable the ansible test service
-  service: name=ansible_test enabled=no
-  register: disable_result
-
-- name: assert that the service was disabled
-  assert:
-    that:
-    - "disable_result.enabled == false"
-
-- name: try to enable a broken service
-  service: name=ansible_broken_test enabled=yes
-  register: broken_enable_result
-  ignore_errors: True
-
-- name: assert that the broken test failed
-  assert:
-    that:
-    - "broken_enable_result is failed"
-
-- name: remove the test daemon script
-  file: path=/usr/sbin/ansible_test_service state=absent
-  register: remove_result
-
-- name: assert that the test daemon script was removed
-  assert:
-    that:
-    - "remove_result.path == '/usr/sbin/ansible_test_service'"
-    - "remove_result.state == 'absent'"
-
-# cleaning up changes made by this playbook
-- include: 'sysv_cleanup.yml'
-  when: service_type == "sysv"
-- include: 'systemd_cleanup.yml'
-  when: service_type == "systemd"
-- include: 'upstart_cleanup.yml'
-  when: service_type == "upstart"
+    # cleaning up changes made by this playbook
+    - include_tasks: '{{ service_type }}_cleanup.yml'
diff --git a/test/integration/targets/service/tasks/systemd_setup.yml b/test/integration/targets/service/tasks/systemd_setup.yml
index bee5ce1f28a..eb944e6f601 100644
--- a/test/integration/targets/service/tasks/systemd_setup.yml
+++ b/test/integration/targets/service/tasks/systemd_setup.yml
@@ -12,6 +12,6 @@
     - "install_systemd_result.dest == '/etc/systemd/system/ansible_test.service'"
     - "install_systemd_result.state == 'file'"
     - "install_systemd_result.mode == '0644'"
-    - "install_systemd_result.checksum == '6b5f2b9318524a387c77c550cef4dd411a471acf'"
+    - "install_systemd_result.checksum == '9e6320795a5c79c01230a6de1c343ea32097af52'"
     - "install_broken_systemd_result.dest == '/etc/systemd/system/ansible_test_broken.service'"
     - "install_broken_systemd_result.state == 'link'"
diff --git a/test/integration/targets/service/tasks/tests.yml b/test/integration/targets/service/tasks/tests.yml
new file mode 100644
index 00000000000..d7e4d7f655a
--- /dev/null
+++ b/test/integration/targets/service/tasks/tests.yml
@@ -0,0 +1,164 @@
+- name: disable the ansible test service
+  service: name=ansible_test enabled=no
+
+- name: (check mode run) enable the ansible test service
+  service: name=ansible_test enabled=yes
+  register: enable_in_check_mode_result
+  check_mode: yes
+
+- name: assert that changes reported for check mode run
+  assert:
+    that:
+      - "enable_in_check_mode_result is changed"
+
+- name: enable the ansible test service
+  service: name=ansible_test enabled=yes
+  register: enable_result
+
+- name: assert that the service was enabled and changes reported
+  assert:
+    that:
+      - "enable_result.enabled == true"
+      - "enable_result is changed"
+
+- name: start the ansible test service
+  service: name=ansible_test state=started
+  register: start_result
+
+- name: assert that the service was started
+  assert:
+    that:
+      - "start_result.state == 'started'"
+      - "start_result is changed"
+
+- name: check that the service was started
+  shell: 'cat /proc/$(cat /var/run/ansible_test_service.pid)/cmdline'
+  register: cmdline
+  failed_when: cmdline is failed or not cmdline.stdout.startswith('python\0/usr/sbin/ansible_test_service\0')
+
+- name: find the service with a pattern
+  service: name=ansible_test pattern="ansible_test_ser" state=started
+  register: start2_result
+
+- name: assert that the service was started via the pattern
+  assert:
+    that:
+      - "start2_result.name == 'ansible_test'"
+      - "start2_result.state == 'started'"
+      - "start2_result is not changed"
+
+- name: fetch PID for ansible_test service (before restart)
+  command: 'cat /var/run/ansible_test_service.pid'
+  register: pid_before_restart
+
+- name: restart the ansible test service
+  service: name=ansible_test state=restarted
+  register: restart_result
+
+- name: assert that the service was restarted
+  assert:
+    that:
+      - "restart_result.state == 'started'"
+      - "restart_result is changed"
+
+- name: fetch PID for ansible_test service (after restart)
+  command: 'cat /var/run/ansible_test_service.pid'
+  register: pid_after_restart
+
+- name: "check that PIDs aren't the same"
+  fail:
+  when: pid_before_restart.stdout == pid_after_restart.stdout
+
+- name: check that service is started
+  command: 'cat /proc/{{ pid_after_restart.stdout }}/cmdline'
+  register: cmdline
+  failed_when: cmdline is failed or not cmdline.stdout.startswith('python\0/usr/sbin/ansible_test_service\0')
+
+- name: restart the ansible test service with a sleep
+  service: name=ansible_test state=restarted sleep=2
+  register: restart_sleep_result
+
+- name: assert that the service was restarted with a sleep
+  assert:
+    that:
+      - "restart_sleep_result.state == 'started'"
+      - "restart_sleep_result is changed"
+
+- name: reload the ansible test service
+  service: name=ansible_test state=reloaded
+  register: reload_result
+  # don't do this on systems with systemd because it triggers error:
+  #   Unable to reload service ansible_test: ansible_test.service is not active, cannot reload.
+  when: service_type != "systemd"
+
+- name: assert that the service was reloaded
+  assert:
+    that:
+      - "reload_result.state == 'started'"
+      - "reload_result is changed"
+  when: service_type != "systemd"
+
+- name: "test for #42786 (sysvinit)"
+  when: service_type == "sysv"
+  block:
+    - name: "sysvinit (#42786): check state, 'enable' parameter isn't set"
+      service: use=sysvinit name=ansible_test state=started
+
+    - name: "sysvinit (#42786): check that service is still enabled"
+      service: use=sysvinit name=ansible_test enabled=yes
+      register: result_enabled
+      failed_when: result_enabled is changed
+
+- name: fetch PID for ansible_test service
+  command: 'cat /var/run/ansible_test_service.pid'
+  register: ansible_test_pid
+
+- name: check that service is started
+  command: 'cat /proc/{{ ansible_test_pid.stdout }}/cmdline'
+  register: cmdline
+  failed_when: cmdline is failed or not cmdline.stdout.startswith('python\0/usr/sbin/ansible_test_service\0')
+
+- name: stop the ansible test service
+  service: name=ansible_test state=stopped
+  register: stop_result
+
+- name: check that the service is stopped
+  command: 'cat /proc/{{ ansible_test_pid.stdout }}/cmdline'
+  register: cmdline
+  failed_when: cmdline is not failed or cmdline.stdout.startswith('python\0/usr/sbin/ansible_test_service\0')
+
+- name: assert that the service was stopped
+  assert:
+    that:
+      - "stop_result.state == 'stopped'"
+      - "stop_result is changed"
+
+- name: disable the ansible test service
+  service: name=ansible_test enabled=no
+  register: disable_result
+
+- name: assert that the service was disabled
+  assert:
+    that:
+      - "disable_result.enabled == false"
+      - "disable_result is changed"
+
+- name: try to enable a broken service
+  service: name=ansible_broken_test enabled=yes
+  register: broken_enable_result
+  ignore_errors: True
+
+- name: assert that the broken test failed
+  assert:
+    that:
+      - "broken_enable_result is failed"
+
+- name: remove the test daemon script
+  file: path=/usr/sbin/ansible_test_service state=absent
+  register: remove_result
+
+- name: assert that the test daemon script was removed
+  assert:
+    that:
+      - "remove_result.path == '/usr/sbin/ansible_test_service'"
+      - "remove_result.state == 'absent'"
diff --git a/test/integration/targets/service/tasks/upstart_cleanup.yml b/test/integration/targets/service/tasks/upstart_cleanup.yml
index a589d5a986e..683fb104aba 100644
--- a/test/integration/targets/service/tasks/upstart_cleanup.yml
+++ b/test/integration/targets/service/tasks/upstart_cleanup.yml
@@ -1,15 +1,17 @@
-- name: remove the upstart init file
-  file: path=/etc/init/ansible_test.conf state=absent
-  register: remove_upstart_result
+- vars:
+    upstart_files:
+      - /etc/init/ansible_test.conf
+      - /etc/init/ansible_test.override
+      - /etc/init/ansible_test_broken.conf
+  block:
+    - name: remove upstart init files
+      file:
+        path: '{{ item }}'
+        state: absent
+      loop: '{{ upstart_files }}'
 
-- name: remove the upstart init file
-  file: path=/etc/init/ansible_test_broken.conf state=absent
-  register: remove_upstart_broken_result
-
-- name: assert that the upstart init file was removed
-  assert:
-    that:
-    - "remove_upstart_result.path == '/etc/init/ansible_test.conf'"
-    - "remove_upstart_result.state == 'absent'"
-    - "remove_upstart_broken_result.path == '/etc/init/ansible_test_broken.conf'"
-    - "remove_upstart_broken_result.state == 'absent'"
+    - name: assert that upstart init files were removed
+      raw: 'test -e {{ item }}'
+      loop: '{{ upstart_files }}'
+      register: file_exists
+      failed_when: file_exists is not failed