From e2856127f654bab808d10bc67531f33fa4243af5 Mon Sep 17 00:00:00 2001
From: Piotr Wojciechowski
 <23406016+WojciechowskiPiotr@users.noreply.github.com>
Date: Sat, 23 Feb 2019 22:59:12 +0100
Subject: [PATCH] Integration test for docker_node module (#52700)

* Integration test for docker_node module

* docker_node integration tests (check_mode and idempotency added)

* docker_node integration tests typos fix
---
 test/integration/targets/docker_node/aliases  |   5 +
 .../targets/docker_node/meta/main.yml         |   3 +
 .../targets/docker_node/tasks/main.yml        |   5 +
 .../targets/docker_node/tasks/test_node.yml   | 839 ++++++++++++++++++
 4 files changed, 852 insertions(+)
 create mode 100644 test/integration/targets/docker_node/aliases
 create mode 100644 test/integration/targets/docker_node/meta/main.yml
 create mode 100644 test/integration/targets/docker_node/tasks/main.yml
 create mode 100644 test/integration/targets/docker_node/tasks/test_node.yml

diff --git a/test/integration/targets/docker_node/aliases b/test/integration/targets/docker_node/aliases
new file mode 100644
index 00000000000..80f0500dfff
--- /dev/null
+++ b/test/integration/targets/docker_node/aliases
@@ -0,0 +1,5 @@
+shippable/posix/group2
+skip/osx
+skip/freebsd
+destructive
+skip/rhel8.0
diff --git a/test/integration/targets/docker_node/meta/main.yml b/test/integration/targets/docker_node/meta/main.yml
new file mode 100644
index 00000000000..07da8c6ddae
--- /dev/null
+++ b/test/integration/targets/docker_node/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+  - setup_docker
diff --git a/test/integration/targets/docker_node/tasks/main.yml b/test/integration/targets/docker_node/tasks/main.yml
new file mode 100644
index 00000000000..19de871b8ff
--- /dev/null
+++ b/test/integration/targets/docker_node/tasks/main.yml
@@ -0,0 +1,5 @@
+- include_tasks: test_node.yml
+  when: docker_py_version is version('1.10.0', '>=') and docker_api_version is version('1.24', '>=')
+
+- fail: msg="Too old docker / docker-py version to run docker_swarm_facts tests!"
+  when: not(docker_py_version is version('1.10.0', '>=') and docker_api_version is version('1.24', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
diff --git a/test/integration/targets/docker_node/tasks/test_node.yml b/test/integration/targets/docker_node/tasks/test_node.yml
new file mode 100644
index 00000000000..ff844f4c7e8
--- /dev/null
+++ b/test/integration/targets/docker_node/tasks/test_node.yml
@@ -0,0 +1,839 @@
+---
+- block:
+  - name: Make sure we're not already using Docker swarm
+    docker_swarm:
+      state: absent
+      force: true
+
+  - name: Try to get docker_node_facts when docker is not running in swarm mode
+    docker_node_facts:
+    ignore_errors: yes
+    register: output
+
+  - name: assert failure when called when swarm is not in use or not run on manager node
+    assert:
+      that:
+         - 'output is failed'
+         - 'output.msg == "Error running docker swarm module: must run on swarm manager node"'
+
+  - name: Create a Swarm cluster
+    docker_swarm:
+      state: present
+    register: output
+
+  - name: assert changed when create a new swarm cluster
+    assert:
+      that:
+         - 'output is changed'
+         - 'output.actions[0] | regex_search("New Swarm cluster created: ")'
+         - 'output.swarm_facts.JoinTokens.Manager'
+         - 'output.swarm_facts.JoinTokens.Worker'
+
+  - name: Try to get docker_node_facts when docker is running in swarm mode and as manager
+    docker_node_facts:
+    register: output
+
+  - name: assert reading docker swarm node facts
+    assert:
+      that:
+         - 'output.nodes_facts | length > 0'
+         - 'output.nodes_facts[0].ID is string'
+
+  - name: Register node ID
+    set_fact:
+      nodeid: "{{ output.nodes_facts[0].ID }}"
+
+####################################################################
+## Set node as swarm manager #######################################
+####################################################################
+
+  - name: Try to set node as manager (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      role: manager
+    check_mode: yes
+    register: set_as_manager_1
+
+  - name: Try to set node as manager
+    docker_node:
+      hostname: "{{ nodeid }}"
+      role: manager
+    register: set_as_manager_2
+
+  - name: Try to set node as manager (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      role: manager
+    register: set_as_manager_3
+
+  - name: Try to set node as manager (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      role: manager
+    check_mode: yes
+    register: set_as_manager_4
+
+  - name: assert that node role does has not changed
+    assert:
+      that:
+         - 'set_as_manager_1 is not changed'
+         - 'set_as_manager_2 is not changed'
+         - 'set_as_manager_3 is not changed'
+         - 'set_as_manager_4 is not changed'
+         - 'set_as_manager_1.node_facts.Spec.Role == "manager"'
+         - 'set_as_manager_2.node_facts.Spec.Role == "manager"'
+         - 'set_as_manager_3.node_facts.Spec.Role == "manager"'
+         - 'set_as_manager_4.node_facts.Spec.Role == "manager"'
+
+####################################################################
+## Set node as swarm worker ########################################
+####################################################################
+
+  - name: Try to set node as worker (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      role: worker
+    check_mode: yes
+    register: set_as_worker_1
+
+  - name: Try to set node as worker
+    docker_node:
+      hostname: "{{ nodeid }}"
+      role: worker
+    ignore_errors: yes
+    register: set_as_worker_2
+
+  - name: assert that node cannot change role to worker
+    assert:
+      that:
+         - 'set_as_worker_1 is changed'
+         - 'set_as_worker_2 is failed'
+         - 'set_as_worker_2.msg | regex_search("attempting to demote the last manager of the swarm")'
+
+####################################################################
+## Set node as pasued ##############################################
+####################################################################
+
+  - name: Try to set node availability as paused  (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      availability: pause
+    check_mode: yes
+    register: set_as_paused_1
+
+  - name: Try to set node availability as paused
+    docker_node:
+      hostname: "{{ nodeid }}"
+      availability: pause
+    register: set_as_paused_2
+
+  - name: Try to set node availability as paused (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      availability: pause
+    register: set_as_paused_3
+
+  - name: Try to set node availability as paused (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      availability: pause
+    check_mode: yes
+    register: set_as_paused_4
+
+  - name: assert node changed availability to paused
+    assert:
+      that:
+         - 'set_as_paused_1 is changed'
+         - 'set_as_paused_2 is changed'
+         - 'set_as_paused_3 is not changed'
+         - 'set_as_paused_4 is not changed'
+         - 'set_as_paused_2.node_facts.Spec.Availability == "pause"'
+
+####################################################################
+## Set node as drained #############################################
+####################################################################
+
+  - name: Try to set node availability as drained (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      availability: drain
+    check_mode: yes
+    register: output_drain_1
+
+  - name: Try to set node availability as drained
+    docker_node:
+      hostname: "{{ nodeid }}"
+      availability: drain
+    register: output_drain_2
+
+  - name: Try to set node availability as drained (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      availability: drain
+    register: output_drain_3
+
+  - name: Try to set node availability as drained (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      availability: drain
+    check_mode: yes
+    register: output_drain_4
+
+  - name: assert node changed availability to drained
+    assert:
+      that:
+         - 'output_drain_1 is changed'
+         - 'output_drain_2 is changed'
+         - 'output_drain_3 is not changed'
+         - 'output_drain_4 is not changed'
+         - 'output_drain_2.node_facts.Spec.Availability == "drain"'
+
+
+####################################################################
+## Set node as active ##############################################
+####################################################################
+
+  - name: Try to set node availability as active (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      availability: active
+    check_mode: yes
+    register: output_active_1
+
+  - name: Try to set node availability as active
+    docker_node:
+      hostname: "{{ nodeid }}"
+      availability: active
+    register: output_active_2
+
+  - name: Try to set node availability as active (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      availability: active
+    register: output_active_3
+
+  - name: Try to set node availability as active (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      availability: active
+    check_mode: yes
+    register: output_active_4
+
+  - name: assert node changed availability to active
+    assert:
+      that:
+         - 'output_active_1 is changed'
+         - 'output_active_2 is changed'
+         - 'output_active_3 is not changed'
+         - 'output_active_4 is not changed'
+         - 'output_active_2.node_facts.Spec.Availability == "active"'
+
+####################################################################
+## Add single label ###############################################
+####################################################################
+
+  - name: Try to add single label to swarm node (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label1: value1
+    check_mode: yes
+    register: output_add_single_label_1
+
+  - name: Try to add single label to swarm node
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label1: value1
+    register: output_add_single_label_2
+
+  - name: Try to add single label to swarm node (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label1: value1
+    register: output_add_single_label_3
+
+  - name: Try to add single label to swarm node (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label1: value1
+    check_mode: yes
+    register: output_add_single_label_4
+
+  - name: assert adding single label to swarm node
+    assert:
+      that:
+         - 'output_add_single_label_1 is changed'
+         - 'output_add_single_label_2 is changed'
+         - 'output_add_single_label_3 is not changed'
+         - 'output_add_single_label_4 is not changed'
+         - 'output_add_single_label_2.node_facts.Spec.Labels | length == 1'
+         - 'output_add_single_label_2.node_facts.Spec.Labels.label1 == "value1"'
+
+####################################################################
+## Add multiple labels #############################################
+####################################################################
+
+  - name: Try to add five labels to swarm node (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label2: value2
+        label3: value3
+        label4: value4
+        label5: value5
+        label6: value6
+    check_mode: yes
+    register: output_add_multiple_labels_1
+
+  - name: Try to add five labels to swarm node
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label2: value2
+        label3: value3
+        label4: value4
+        label5: value5
+        label6: value6
+    register: output_add_multiple_labels_2
+
+  - name: Try to add five labels to swarm node (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label2: value2
+        label3: value3
+        label4: value4
+        label5: value5
+        label6: value6
+    register: output_add_multiple_labels_3
+
+  - name: Try to add five labels to swarm node (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label2: value2
+        label3: value3
+        label4: value4
+        label5: value5
+        label6: value6
+    check_mode: yes
+    register: output_add_multiple_labels_4
+
+  - name: assert adding multiple labels to swarm node
+    assert:
+      that:
+         - 'output_add_multiple_labels_1 is changed'
+         - 'output_add_multiple_labels_2 is changed'
+         - 'output_add_multiple_labels_3 is not changed'
+         - 'output_add_multiple_labels_4 is not changed'
+         - 'output_add_multiple_labels_2.node_facts.Spec.Labels | length == 6'
+         - 'output_add_multiple_labels_2.node_facts.Spec.Labels.label1 == "value1"'
+         - 'output_add_multiple_labels_2.node_facts.Spec.Labels.label6 == "value6"'
+
+####################################################################
+## Update label value ##############################################
+####################################################################
+
+  - name: Update value of existing label (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label1: value1111
+    check_mode: yes
+    register: output_update_label_1
+
+  - name: Update value of existing label
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label1: value1111
+    register: output_update_label_2
+
+  - name: Update value of existing label (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label1: value1111
+    register: output_update_label_3
+
+  - name: Update value of existing label (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label1: value1111
+    check_mode: yes
+    register: output_update_label_4
+
+  - name: assert updating single label assigned to swarm node
+    assert:
+      that:
+         - 'output_update_label_1 is changed'
+         - 'output_update_label_2 is changed'
+         - 'output_update_label_3 is not changed'
+         - 'output_update_label_4 is not changed'
+         - 'output_update_label_2.node_facts.Spec.Labels | length == 6'
+         - 'output_update_label_2.node_facts.Spec.Labels.label1 == "value1111"'
+         - 'output_update_label_2.node_facts.Spec.Labels.label5 == "value5"'
+
+####################################################################
+## Update multiple labels values ###################################
+####################################################################
+
+  - name: Update value of multiple existing label (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label2: value2222
+        label3: value3333
+    check_mode: yes
+    register: output_update_labels_1
+
+  - name: Update value of multiple existing label
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label2: value2222
+        label3: value3333
+    register: output_update_labels_2
+
+  - name: Update value of multiple existing label (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label2: value2222
+        label3: value3333
+    register: output_update_labels_3
+
+  - name: Update value of multiple existing label (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label2: value2222
+        label3: value3333
+    check_mode: yes
+    register: output_update_labels_4
+
+  - name: assert updating multiple labels assigned to swarm node
+    assert:
+      that:
+         - 'output_update_labels_1 is changed'
+         - 'output_update_labels_2 is changed'
+         - 'output_update_labels_3 is not changed'
+         - 'output_update_labels_4 is not changed'
+         - 'output_update_labels_2.node_facts.Spec.Labels | length == 6'
+         - 'output_update_labels_2.node_facts.Spec.Labels.label1 == "value1111"'
+         - 'output_update_labels_2.node_facts.Spec.Labels.label3 == "value3333"'
+         - 'output_update_labels_2.node_facts.Spec.Labels.label5 == "value5"'
+
+####################################################################
+## Remove single label #############################################
+####################################################################
+
+  - name: Try to remove single existing label from swarm node (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - label1
+    check_mode: yes
+    register: output_remove_label_1
+
+  - name: Try to remove single existing label from swarm node
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - label1
+    register: output_remove_label_2
+
+  - name: Try to remove single existing label from swarm node (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - label1
+    register: output_remove_label_3
+
+  - name: Try to remove single existing label from swarm node (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - label1
+    check_mode: yes
+    register: output_remove_label_4
+
+  - name: assert removing single label from swarm node
+    assert:
+      that:
+         - 'output_remove_label_1 is changed'
+         - 'output_remove_label_2 is changed'
+         - 'output_remove_label_3 is not changed'
+         - 'output_remove_label_4 is not changed'
+         - 'output_remove_label_2.node_facts.Spec.Labels | length == 5'
+         - '"label1" not in output_remove_label_2.node_facts.Spec.Labels'
+         - 'output_remove_label_2.node_facts.Spec.Labels.label3 == "value3333"'
+         - 'output_remove_label_2.node_facts.Spec.Labels.label5 == "value5"'
+
+
+####################################################################
+## Remove single not assigned to swarm label #######################
+####################################################################
+
+  - name: Try to remove single non-existing label from swarm node (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - labelnotexist
+    check_mode: yes
+    register: output_remove_nonexist_label_1
+
+  - name: Try to remove single non-existing label from swarm node
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - labelnotexist
+    register: output_remove_nonexist_label_2
+
+  - name: Try to remove single non-existing label from swarm node (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - labelnotexist
+    register: output_remove_nonexist_label_3
+
+  - name: Try to remove single non-existing label from swarm node (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - labelnotexist
+    check_mode: yes
+    register: output_remove_nonexist_label_4
+
+  - name: assert removing single non-existing label from swarm node
+    assert:
+      that:
+         - 'output_remove_nonexist_label_1 is not changed'
+         - 'output_remove_nonexist_label_2 is not changed'
+         - 'output_remove_nonexist_label_3 is not changed'
+         - 'output_remove_nonexist_label_4 is not changed'
+         - 'output_remove_nonexist_label_2.node_facts.Spec.Labels | length == 5'
+         - '"label1" not in output_remove_nonexist_label_2.node_facts.Spec.Labels'
+         - 'output_remove_nonexist_label_2.node_facts.Spec.Labels.label3 == "value3333"'
+         - 'output_remove_nonexist_label_2.node_facts.Spec.Labels.label5 == "value5"'
+
+####################################################################
+## Remove multiple labels ##########################################
+####################################################################
+
+  - name: Try to remove two existing labels from swarm node (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - label2
+        - label3
+    check_mode: yes
+    register: output_remove_label_1
+
+  - name: Try to remove two existing labels from swarm node
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - label2
+        - label3
+    register: output_remove_label_2
+
+  - name: Try to remove two existing labels from swarm node (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - label2
+        - label3
+    register: output_remove_label_3
+
+  - name: Try to remove two existing labels from swarm node (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - label2
+        - label3
+    check_mode: yes
+    register: output_remove_label_4
+
+  - name: assert removing multiple labels from swarm node
+    assert:
+      that:
+         - 'output_remove_label_1 is changed'
+         - 'output_remove_label_2 is changed'
+         - 'output_remove_label_3 is not changed'
+         - 'output_remove_label_4 is not changed'
+         - 'output_remove_label_2.node_facts.Spec.Labels | length == 3'
+         - '"label1" not in output_remove_label_2.node_facts.Spec.Labels'
+         - '"label2" not in output_remove_label_2.node_facts.Spec.Labels'
+         - 'output_remove_label_2.node_facts.Spec.Labels.label5 == "value5"'
+
+####################################################################
+## Remove multiple labels, mix assigned and not assigned  ##########
+####################################################################
+
+  - name: Try to remove mix of existing amd non-existing labels from swarm node (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - label4
+        - labelisnotthere
+    check_mode: yes
+    register: output_remove_mix_labels_1
+
+  - name: Try to remove mix of existing amd non-existing labels from swarm node
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - label4
+        - labelisnotthere
+    register: output_remove_mix_labels_2
+
+  - name: Try to remove mix of existing amd non-existing labels from swarm node (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - label4
+        - labelisnotthere
+    register: output_remove_mix_labels_3
+
+  - name: Try to remove mix of existing amd non-existing labels from swarm node (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_to_remove:
+        - label4
+        - labelisnotthere
+    check_mode: yes
+    register: output_remove_mix_labels_4
+
+  - name: assert removing mix of existing and non-existing labels from swarm node
+    assert:
+      that:
+        - 'output_remove_mix_labels_1 is changed'
+        - 'output_remove_mix_labels_2 is changed'
+        - 'output_remove_mix_labels_3 is not changed'
+        - 'output_remove_mix_labels_4 is not changed'
+        - 'output_remove_mix_labels_2.node_facts.Spec.Labels | length == 2'
+        - '"label1" not in output_remove_mix_labels_2.node_facts.Spec.Labels'
+        - '"label4" not in output_remove_mix_labels_2.node_facts.Spec.Labels'
+        - 'output_remove_mix_labels_2.node_facts.Spec.Labels.label5 == "value5"'
+
+####################################################################
+## Add and remove labels ###########################################
+####################################################################
+
+  - name: Try to add and remove nonoverlapping labels at the same time (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label7: value7
+        label8: value8
+      labels_to_remove:
+        - label5
+    check_mode: yes
+    register: output_add_del_labels_1
+
+  - name: Try to add and remove nonoverlapping labels at the same time
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label7: value7
+        label8: value8
+      labels_to_remove:
+        - label5
+    register: output_add_del_labels_2
+
+  - name: Try to add and remove nonoverlapping labels at the same time (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label7: value7
+        label8: value8
+      labels_to_remove:
+        - label5
+    register: output_add_del_labels_3
+
+  - name: Try to add and remove nonoverlapping labels at the same time (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label7: value7
+        label8: value8
+      labels_to_remove:
+        - label5
+    check_mode: yes
+    register: output_add_del_labels_4
+
+  - name: assert adding and removing nonoverlapping labels from swarm node
+    assert:
+      that:
+        - 'output_add_del_labels_1 is changed'
+        - 'output_add_del_labels_2 is changed'
+        - 'output_add_del_labels_3 is not changed'
+        - 'output_add_del_labels_4 is not changed'
+        - 'output_add_del_labels_2.node_facts.Spec.Labels | length == 3'
+        - '"label5" not in output_add_del_labels_2.node_facts.Spec.Labels'
+        - 'output_add_del_labels_2.node_facts.Spec.Labels.label8 == "value8"'
+
+####################################################################
+## Add and remove labels with label in both lists ##################
+####################################################################
+
+  - name: Try to add or update and remove overlapping labels at the same time (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label22: value22
+        label6: value6666
+      labels_to_remove:
+        - label6
+        - label7
+    check_mode: yes
+    register: output_add_del_overlap_lables_1
+
+  - name: Try to add or update and remove overlapping labels at the same time
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label22: value22
+        label6: value6666
+      labels_to_remove:
+        - label6
+        - label7
+    register: output_add_del_overlap_lables_2
+
+  - name: Try to add or update and remove overlapping labels at the same time (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label22: value22
+        label6: value6666
+      labels_to_remove:
+        - label6
+        - label7
+    register: output_add_del_overlap_lables_3
+
+  - name: Try to add or update and remove overlapping labels at the same time (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label22: value22
+        label6: value6666
+      labels_to_remove:
+        - label6
+        - label7
+    check_mode: yes
+    register: output_add_del_overlap_lables_4
+
+  - name: assert adding or updating and removing overlapping labels from swarm node
+    assert:
+      that:
+        - 'output_add_del_overlap_lables_1 is changed'
+        - 'output_add_del_overlap_lables_2 is changed'
+        - 'output_add_del_overlap_lables_3 is not changed'
+        - 'output_add_del_overlap_lables_4 is not changed'
+        - 'output_add_del_overlap_lables_2.node_facts.Spec.Labels | length == 3'
+        - '"label7" not in output_add_del_overlap_lables_2.node_facts.Spec.Labels'
+        - 'output_add_del_overlap_lables_2.node_facts.Spec.Labels.label6 == "value6666"'
+        - 'output_add_del_overlap_lables_2.node_facts.Spec.Labels.label22 == "value22"'
+
+####################################################################
+## Replace labels #############################################
+####################################################################
+
+  - name: Replace labels on swarm node (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label11: value11
+        label12: value12
+      labels_state: replace
+    check_mode: yes
+    register: output_replace_labels_1
+
+  - name: Replace labels on swarm node
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label11: value11
+        label12: value12
+      labels_state: replace
+    register: output_replace_labels_2
+
+  - name: Replace labels on swarm node (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label11: value11
+        label12: value12
+      labels_state: replace
+    register: output_replace_labels_3
+
+  - name: Replace labels on swarm node (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels:
+        label11: value11
+        label12: value12
+      labels_state: replace
+    check_mode: yes
+    register: output_replace_labels_4
+
+  - name: assert replacing labels from swarm node
+    assert:
+      that:
+        - 'output_replace_labels_1 is changed'
+        - 'output_replace_labels_2 is changed'
+        - 'output_replace_labels_3 is not changed'
+        - 'output_replace_labels_4 is not changed'
+        - 'output_replace_labels_2.node_facts.Spec.Labels | length == 2'
+        - '"label6" not in output_replace_labels_2.node_facts.Spec.Labels'
+        - 'output_replace_labels_2.node_facts.Spec.Labels.label12 == "value12"'
+
+####################################################################
+## Remove all labels #############################################
+####################################################################
+
+  - name: Remove all labels from swarm node (check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_state: replace
+    check_mode: yes
+    register: output_remove_labels_1
+
+  - name: Remove all labels from swarm node
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_state: replace
+    register: output_remove_labels_2
+
+  - name: Remove all labels from swarm node (idempotent)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_state: replace
+    register: output_remove_labels_3
+
+  - name: Remove all labels from swarm node (idempotent check)
+    docker_node:
+      hostname: "{{ nodeid }}"
+      labels_state: replace
+    check_mode: yes
+    register: output_remove_labels_4
+
+  - name: assert removing all lables from swarm node
+    assert:
+      that:
+        - 'output_remove_labels_1 is changed'
+        - 'output_remove_labels_2 is changed'
+        - 'output_remove_labels_3 is not changed'
+        - 'output_remove_labels_4 is not changed'
+        - 'output_remove_labels_2.node_facts.Spec.Labels | length == 0'
+
+  always:
+  - name: Cleanup
+    docker_swarm:
+      state: absent
+      force: true