diff --git a/azure-pipelines.yml b/azure-pipelines.yml
deleted file mode 100644
index fa73f4a433c2cdd232f90397421b1e6fcdd90f31..0000000000000000000000000000000000000000
--- a/azure-pipelines.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-trigger:
-- master
-
-pool:
-  vmImage: 'ubuntu-18.04'
-
-steps:
-- task: UsePythonVersion@0
-  inputs:
-    versionSpec: '3.6'
-
-- script: python -m pip install --upgrade pip setuptools wheel
-  displayName: Install tools
-
-- script: pip install pydocstyle flake8
-  displayName: Install dependencies
-
-- script: flake8 .
-  displayName: Run flake8 checks
-
-- script: pydocstyle .
-  displayName: Verify docstings
diff --git a/molecule/centos-7-build/molecule.yml b/molecule/centos-7-build/molecule.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0360b8cc2206c8e5c8ba696028262159d0d62040
--- /dev/null
+++ b/molecule/centos-7-build/molecule.yml
@@ -0,0 +1,20 @@
+---
+dependency:
+  name: galaxy
+driver:
+  name: docker
+platforms:
+  - name: centos-7-build
+    image: centos/systemd
+    pre_build_image: true
+    hostname: ipaserver.test.local
+    dns_servers:
+      - 8.8.8.8
+    volumes:
+      - /sys/fs/cgroup:/sys/fs/cgroup:ro
+    command: /usr/sbin/init
+    privileged: true
+provisioner:
+  name: ansible
+  playbooks:
+    prepare: ../resources/playbooks/prepare-build.yml
diff --git a/molecule/centos-7/molecule.yml b/molecule/centos-7/molecule.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0603e267605af13ec94cd328829cf256e7f690b5
--- /dev/null
+++ b/molecule/centos-7/molecule.yml
@@ -0,0 +1,20 @@
+---
+dependency:
+  name: galaxy
+driver:
+  name: docker
+platforms:
+  - name: centos-7
+    image: quay.io/ansible-freeipa/upstream-tests:centos-7
+    pre_build_image: true
+    hostname: ipaserver.test.local
+    dns_servers:
+      - 127.0.0.1
+    volumes:
+      - /sys/fs/cgroup:/sys/fs/cgroup:ro
+    command: /usr/sbin/init
+    privileged: true
+provisioner:
+  name: ansible
+  playbooks:
+    prepare: ../resources/playbooks/prepare.yml
diff --git a/molecule/centos-8-build/molecule.yml b/molecule/centos-8-build/molecule.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a7ffacdfa8caa09d62e66fade483224a561bddc6
--- /dev/null
+++ b/molecule/centos-8-build/molecule.yml
@@ -0,0 +1,20 @@
+---
+dependency:
+  name: galaxy
+driver:
+  name: docker
+platforms:
+  - name: centos-8-build
+    image: centos:8
+    pre_build_image: true
+    hostname: ipaserver.test.local
+    dns_servers:
+      - 8.8.8.8
+    volumes:
+      - /sys/fs/cgroup:/sys/fs/cgroup:ro
+    command: /usr/sbin/init
+    privileged: true
+provisioner:
+  name: ansible
+  playbooks:
+    prepare: ../resources/playbooks/prepare-build.yml
diff --git a/molecule/centos-8/molecule.yml b/molecule/centos-8/molecule.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4e1ab7930258cd43312471abb3e5ca6776f567bf
--- /dev/null
+++ b/molecule/centos-8/molecule.yml
@@ -0,0 +1,20 @@
+---
+dependency:
+  name: galaxy
+driver:
+  name: docker
+platforms:
+  - name: centos-8
+    image: quay.io/ansible-freeipa/upstream-tests:centos-8
+    pre_build_image: true
+    hostname: ipaserver.test.local
+    dns_servers:
+      - 127.0.0.1
+    volumes:
+      - /sys/fs/cgroup:/sys/fs/cgroup:ro
+    command: /usr/sbin/init
+    privileged: true
+provisioner:
+  name: ansible
+  playbooks:
+    prepare: ../resources/playbooks/prepare.yml
diff --git a/molecule/default b/molecule/default
new file mode 120000
index 0000000000000000000000000000000000000000..e0a5460530c6acf9e12572ce5cf8c2d8123a4d4d
--- /dev/null
+++ b/molecule/default
@@ -0,0 +1 @@
+/home/scampos/src/ansible-freeipa/molecule/centos-8
\ No newline at end of file
diff --git a/molecule/resources/playbooks/library b/molecule/resources/playbooks/library
new file mode 120000
index 0000000000000000000000000000000000000000..b30cd0957254fc0aa0ce8c568ee5f0450a9af42b
--- /dev/null
+++ b/molecule/resources/playbooks/library
@@ -0,0 +1 @@
+/home/scampos/src/ansible-freeipa/plugins/modules/
\ No newline at end of file
diff --git a/molecule/resources/playbooks/module_utils b/molecule/resources/playbooks/module_utils
new file mode 120000
index 0000000000000000000000000000000000000000..4a88d1e6dd11dc68a2e82720de04d2216c089a7e
--- /dev/null
+++ b/molecule/resources/playbooks/module_utils
@@ -0,0 +1 @@
+/home/scampos/src/ansible-freeipa/plugins/module_utils/
\ No newline at end of file
diff --git a/molecule/resources/playbooks/prepare-build.yml b/molecule/resources/playbooks/prepare-build.yml
new file mode 100644
index 0000000000000000000000000000000000000000..784fe7e3b27d2374ff528ed7c2a7c8dc0e99696f
--- /dev/null
+++ b/molecule/resources/playbooks/prepare-build.yml
@@ -0,0 +1,54 @@
+---
+- name: Converge
+  hosts: all
+  tasks:
+  - name: Ensure IPv6 is ENABLED
+    sysctl:
+      name: "{{ item.name }}"
+      value: "{{ item.value }}"
+      sysctl_set: yes
+      state: present
+      reload: yes
+    with_items :
+      - name: net.ipv6.conf.all.disable_ipv6
+        value: 0
+      - name: net.ipv6.conf.lo.disable_ipv6
+        value: 0
+      - name: net.ipv6.conf.eth0.disable_ipv6
+        value: 1
+
+  - name: stat protected_regular
+    stat:
+      path: /proc/sys/fs/protected_regular
+    register: result
+
+  - name: Ensure fs.protected_regular is disabled
+    sysctl:
+      name: fs.protected_regular
+      value: 0
+      sysctl_set: yes
+      state: present
+      reload: yes
+    when: result.stat.exists
+
+  - name: Ensure sudo package is installed
+    package:
+      name: sudo
+
+  - name: Ensure nss package is updated
+    package:
+      name: nss
+      state: latest
+
+  - include_role:
+      name: ipaserver
+    vars:
+      ipaserver_setup_dns: yes
+      ipaserver_setup_kra: yes
+      ipaserver_auto_forwarders: yes
+      ipaserver_no_dnssec_validation: yes
+      ipaserver_auto_reverse: yes
+      ipaadmin_password: SomeADMINpassword
+      ipadm_password: SomeDMpassword
+      ipaserver_domain: test.local
+      ipaserver_realm: TEST.LOCAL
diff --git a/molecule/resources/playbooks/prepare.yml b/molecule/resources/playbooks/prepare.yml
new file mode 100644
index 0000000000000000000000000000000000000000..fc564d0115f1b21df4a3b7293eac1c1ee7ea3c27
--- /dev/null
+++ b/molecule/resources/playbooks/prepare.yml
@@ -0,0 +1,18 @@
+---
+- name: Converge
+  hosts: all
+  tasks:
+  - name: Ensure lock dirs for DS exists
+    file:
+      state: directory
+      owner: dirsrv
+      group: dirsrv
+      path: "{{ item }} "
+    loop:
+      - /var/lock/dirsrv/
+      - /var/lock/dirsrv/slapd-TEST-LOCAL/
+
+  - name: Ensure IPA server is up an running
+    service:
+      name: ipa
+      state: started
diff --git a/molecule/resources/playbooks/roles b/molecule/resources/playbooks/roles
new file mode 120000
index 0000000000000000000000000000000000000000..a0123be0f4b0ccc25e0171e10886e1024235069e
--- /dev/null
+++ b/molecule/resources/playbooks/roles
@@ -0,0 +1 @@
+/home/scampos/src/ansible-freeipa/roles
\ No newline at end of file
diff --git a/pytest.ini b/pytest.ini
index 0ee949b8988aaae11d6e2dfdb15f941753f2b065..1e6a19218b7818d3bcc256f5796c1cb3b562a3c3 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,2 +1,3 @@
 [pytest]
 python_files = test_*.py
+junit_family = xunit1
diff --git a/tests/README.md b/tests/README.md
index d187575e3987b72d88df82104083b4fc920088ed..2c00436add2f740264b1ccb9a919e1b1ffdc2579 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -29,7 +29,13 @@ environment variable. For example:
 ANSIBLE_REMOTE_USER=root IPA_SERVER_HOST=<ipaserver_host_or_ip> pytest
 ```
 
-To select which tests to run use the option `-k`. For example:
+To run a single test use the full path with the following format:
+
+```
+IPA_SERVER_HOST=<ipaserver_host_or_ip> pytest tests/test_playbook_runs.py::sudorule::test_sudorule
+```
+
+To select which tests to run based on search use the option `-k`. For example:
 
 ```
 IPA_SERVER_HOST=<ipaserver_host_or_ip> pytest -k dnszone
@@ -50,6 +56,45 @@ IPA_SERVER_HOST=<ipaserver_host_or_ip> pytest -rs
 For a complete list of options check `pytest --help`.
 
 
+## Running tests in a docker container
+
+It's also possible to run the tests in a container.
+
+### Creating a container to run the tests
+
+Before setting up a container you will need to install molecule framework:
+
+```
+pip install molecule[docker]>=3
+```
+
+Now you can start a test container using the following command:
+```
+molecule create -s centos-8
+```
+
+Note: Currently the containers available for running the tests are:
+ * centos-7
+ * centos-8
+
+### Running the tests inside the container
+
+To run the tests you will use pytest (works the same as for VMs).
+
+```
+RUN_TESTS_IN_DOCKER=1 IPA_SERVER_HOST=centos-8 pytest
+```
+
+### Cleaning up after tests
+
+After running the tests you should probably destroy the test container using:
+
+```
+molecule destroy -s centos-8
+```
+
+See [Running the tests](#running-the-tests) section for more information on available options.
+
 ## Upcoming/desired improvements:
 
 * A script to pre-config the complete test environment using virsh.
diff --git a/tests/azure/azure-pipelines.yml b/tests/azure/azure-pipelines.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9a6321050ce8496f818f4f69c5185e3c90236027
--- /dev/null
+++ b/tests/azure/azure-pipelines.yml
@@ -0,0 +1,56 @@
+# Using Ansible 2.10.0a1 under Azure there might happen that the output of a
+# task is changed if a module uses no_log = True for an attribute.
+#
+# For example, if the output of the module should contain "changed: True", and
+# an attribute with no_log set contains the value `hang` it might happen that
+# the output is modified to "c******ed: True", and if this output is further
+# processed (registering the result and comparing the value of `changed`),
+# the test might fail, but not because of module code, but because of unexpected
+# output processing.
+#
+# This behavior was, currently, only reproduced with Ansible 2.10.0a1 running
+# under Azure.
+---
+trigger:
+- master
+
+pool:
+  vmImage: 'ubuntu-18.04'
+
+jobs:
+- job: RunLinters
+  displayName: Run Linters
+  steps:
+  - task: UsePythonVersion@0
+    inputs:
+      versionSpec: '3.6'
+
+  - script: python -m pip install --upgrade pip setuptools wheel
+    displayName: Install tools
+
+  - script: pip install pydocstyle flake8
+    displayName: Install dependencies
+
+  - script: flake8 .
+    displayName: Run flake8 checks
+
+  - script: pydocstyle .
+    displayName: Verify docstings
+
+- template: templates/playbook_tests.yml
+  parameters:
+    group_number: 1
+    number_of_groups: 3
+    build_number: $(Build.BuildNumber)
+
+- template: templates/playbook_tests.yml
+  parameters:
+    group_number: 2
+    number_of_groups: 3
+    build_number: $(Build.BuildNumber)
+
+- template: templates/playbook_tests.yml
+  parameters:
+    group_number: 3
+    number_of_groups: 3
+    build_number: $(Build.BuildNumber)
diff --git a/tests/azure/templates/playbook_tests.yml b/tests/azure/templates/playbook_tests.yml
new file mode 100644
index 0000000000000000000000000000000000000000..929f2ffced504871bec0dcdc3d5be0b7a0651081
--- /dev/null
+++ b/tests/azure/templates/playbook_tests.yml
@@ -0,0 +1,61 @@
+
+parameters:
+  - name: group_number
+    type: number
+    default: 1
+  - name: number_of_groups
+    type: number
+    default: 1
+  - name: scenario
+    type: string
+    default: centos-8
+  - name: ansible_version
+    type: string
+    default: ">=2.9,<2.10"
+  - name: python_version
+    type: string
+    default: 3.6
+  - name: build_number
+
+jobs:
+- job: RunTests${{ parameters.group_number }}
+  displayName: Run tests ${{ parameters.group_number }}/${{ parameters.number_of_groups }}
+  steps:
+  - task: UsePythonVersion@0
+    inputs:
+      versionSpec: '${{ parameters.python_version }}'
+
+  - script: |
+      pip install \
+        "molecule[docker]>=3" \
+        "ansible${{ parameters.ansible_version }}" \
+        pytest \
+        pytest-split-tests
+    displayName: Install dependencies
+
+  - script: |
+      mkdir -p ~/.ansible/roles ~/.ansible/library ~/.ansible/module_utils
+      cp -a roles/* ~/.ansible/roles
+      cp -a plugins/modules/* ~/.ansible/library
+      cp -a plugins/module_utils/* ~/.ansible/module_utils
+      molecule create -s ${{ parameters.scenario }}
+    displayName: Setup test container
+
+  - script: |
+      pytest \
+        --verbose \
+        --color=yes \
+        --test-group-count=${{ parameters.number_of_groups }} \
+        --test-group=${{ parameters.group_number }} \
+        --test-group-random-seed=97943259814 \
+        --junit-xml=TEST-results-group-${{ parameters.group_number }}.xml
+    displayName: Run playbook tests
+    env:
+      IPA_SERVER_HOST: ${{ parameters.scenario }}
+      RUN_TESTS_IN_DOCKER: true
+
+  - task: PublishTestResults@2
+    inputs:
+      mergeTestResults: true
+      testRunTitle: PlaybookTests-Build${{ parameters.build_number }}
+    condition: succeededOrFailed()
diff --git a/tests/ca-less/clean_up_certificates.yml b/tests/ca-less/clean_up_certificates.yml
index ea8a4e8ee714efbe9dd95f792eb92d11964c6eda..23c025b381bfa97e74285a0ac0a6050c9793d871 100644
--- a/tests/ca-less/clean_up_certificates.yml
+++ b/tests/ca-less/clean_up_certificates.yml
@@ -12,4 +12,4 @@
       chdir: "{{ playbook_dir }}"
     with_items:
       - "{{ groups.ipaserver[0] }}"
-      - "{{ groups.ipareplicas[0] }}"
\ No newline at end of file
+      - "{{ groups.ipareplicas[0] }}"
diff --git a/tests/dnsrecord/env_cleanup.yml b/tests/dnsrecord/env_cleanup.yml
index 5b9b7343ff80d9603e91c6c79799054fcb425132..c5890fa0ba33db6a6ed280e366f9bf09c01d8564 100644
--- a/tests/dnsrecord/env_cleanup.yml
+++ b/tests/dnsrecord/env_cleanup.yml
@@ -129,7 +129,7 @@
        - "{{ zone_prefix_reverse_24 }}"
        - "{{ zone_prefix_reverse_16 }}"
        - "{{ zone_prefix_reverse_8 }}"
+       - "{{ zone_ipv6_reverse }}"
+       - "{{ zone_ipv6_reverse_workaround }}"
        - "{{ testzone }}"
-       - ip6.arpa.
-       - d.f.ip6.arpa.
        - "{{ safezone }}"
diff --git a/tests/dnsrecord/env_setup.yml b/tests/dnsrecord/env_setup.yml
index d9a8546b991b99ed51c635e88851558245e64b5a..ebdb7570fd08081b977c8ea1da3fa1fb901e1304 100644
--- a/tests/dnsrecord/env_setup.yml
+++ b/tests/dnsrecord/env_setup.yml
@@ -18,8 +18,9 @@
     - "{{ zone_prefix_reverse_24 }}"
     - "{{ zone_prefix_reverse_16 }}"
     - "{{ zone_prefix_reverse_8 }}"
+    - "{{ zone_ipv6_reverse_workaround }}"
     - "{{ testzone }}"
-    - ip6.arpa.
+    - "{{ zone_ipv6_reverse }}"
 
   - name: Ensure DNSSEC zone '"{{ safezone }}"' is present.
     ipadnszone:
diff --git a/tests/dnsrecord/env_vars.yml b/tests/dnsrecord/env_vars.yml
index bb540a0a9447153f5db7b4fd6126ba19f548f845..d3aef920351e65c948b62c9558bbfa849f0ca9e3 100644
--- a/tests/dnsrecord/env_vars.yml
+++ b/tests/dnsrecord/env_vars.yml
@@ -2,8 +2,11 @@
 # Set common vars and facts for test.
 - name: Set IPv4 address prefix.
   set_fact:
-    ipv4_prefix: '192.168.122'
-    ipv4_reverse_sufix: '122.168.192'
+    ipv4_prefix: "{{ ansible_default_ipv4.address.split('.')[:-1] |
+                     join('.') }}"
+    ipv4_reverse_sufix: "{{ ansible_default_ipv4.address.split('.')[:-1] |
+                            reverse |
+                            join('.') }}"
 
 - name: Set zone prefixes.
   set_fact:
diff --git a/tests/external-signed-ca-with-automatic-copy/install-server-with-external-ca-with-automatic-copy.yml b/tests/external-signed-ca-with-automatic-copy/install-server-with-external-ca-with-automatic-copy.yml
index e856fb40f8f148d1abe1975908f3d52a83be7939..02e20d951d4d103cee61a69dbce3f87c16f77a4b 100644
--- a/tests/external-signed-ca-with-automatic-copy/install-server-with-external-ca-with-automatic-copy.yml
+++ b/tests/external-signed-ca-with-automatic-copy/install-server-with-external-ca-with-automatic-copy.yml
@@ -12,7 +12,6 @@
 
 - name: Create CA, get /root/ipa.csr signed by your CA, ..
   hosts: localhost
-  gather_facts: false
 
   tasks:
   - name: Run external-ca.sh
diff --git a/tests/external-signed-ca-with-manual-copy/install-server-with-external-ca-with-manual-copy.yml b/tests/external-signed-ca-with-manual-copy/install-server-with-external-ca-with-manual-copy.yml
index 33b466ca2581cce976f75236be010a11a305ccc6..19cea6b866022615a1f40ade9fa24df0bb9864cd 100644
--- a/tests/external-signed-ca-with-manual-copy/install-server-with-external-ca-with-manual-copy.yml
+++ b/tests/external-signed-ca-with-manual-copy/install-server-with-external-ca-with-manual-copy.yml
@@ -18,7 +18,6 @@
 
 - name: Get /root/ipa.csr, create CA, sign with our CA and copy to node
   hosts: localhost
-  gather_facts: false
 
   tasks:
   - name: Run external-ca.sh
diff --git a/tests/hbacrule/test_hbacrule.yml b/tests/hbacrule/test_hbacrule.yml
index 4d0c203004920e6a15daf99c94c5f219604b0058..ce1f29c5743fdad46aac8700a1ae7bf3026514c8 100644
--- a/tests/hbacrule/test_hbacrule.yml
+++ b/tests/hbacrule/test_hbacrule.yml
@@ -6,7 +6,7 @@
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   # CLEANUP TEST ITEMS
diff --git a/tests/host/certificate/test_host_certificate.yml b/tests/host/certificate/test_host_certificate.yml
index 7607006f1f0309abfdcde0ada0478ac7878f3854..aa50eb27bd84f2a6893f30f96a6d90aaafa6af58 100644
--- a/tests/host/certificate/test_host_certificate.yml
+++ b/tests/host/certificate/test_host_certificate.yml
@@ -21,12 +21,11 @@
 - name: Test host certificates
   hosts: ipaserver
   become: true
-  gather_facts: false
 
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Host test absent
diff --git a/tests/host/certificate/test_hosts_certificate.yml b/tests/host/certificate/test_hosts_certificate.yml
index 853762c6c649ca5e8d936728b81252bbcbebc0b9..44c63ef006d23f60300f1f6092fbfe95e702224f 100644
--- a/tests/host/certificate/test_hosts_certificate.yml
+++ b/tests/host/certificate/test_hosts_certificate.yml
@@ -21,12 +21,11 @@
 - name: Test host certificates
   hosts: ipaserver
   become: true
-  gather_facts: false
 
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Host test absent
diff --git a/tests/host/test_host.yml b/tests/host/test_host.yml
index efb0524af9df53dd9705dd4c432495fe4bf4b90c..d4760c1887109cb1f811b8863e4afc5f7762d0b6 100644
--- a/tests/host/test_host.yml
+++ b/tests/host/test_host.yml
@@ -6,7 +6,7 @@
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Set host1_fqdn .. host6_fqdn
diff --git a/tests/host/test_host_allow_create_keytab.yml b/tests/host/test_host_allow_create_keytab.yml
index b9ad0a190d32511d827b64e3d45cc237b549cde8..4be1305ec117d77c2ee7583d016a5aab20884800 100644
--- a/tests/host/test_host_allow_create_keytab.yml
+++ b/tests/host/test_host_allow_create_keytab.yml
@@ -6,12 +6,12 @@
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Get Realm from server name
     set_fact:
-      ipaserver_realm: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') | upper }}"
+      ipaserver_realm: "{{ ansible_fqdn.split('.')[1:] | join ('.') | upper }}"
     when: ipaserver_realm is not defined
 
   - name: Set host1_fqdn .. host3_fqdn
diff --git a/tests/host/test_host_allow_retrieve_keytab.yml b/tests/host/test_host_allow_retrieve_keytab.yml
index 8f95540733bcc1a4db504cf972cc9e6ac84c25c9..9be0ef6189f0d686bb62ee6ea93d594124d42a93 100644
--- a/tests/host/test_host_allow_retrieve_keytab.yml
+++ b/tests/host/test_host_allow_retrieve_keytab.yml
@@ -6,12 +6,12 @@
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Get Realm from server name
     set_fact:
-      ipaserver_realm: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') | upper }}"
+      ipaserver_realm: "{{ ansible_fqdn.split('.')[1:] | join ('.') | upper }}"
     when: ipaserver_realm is not defined
 
   - name: Set host1_fqdn .. host3_fqdn
diff --git a/tests/host/test_host_bool_params.yml b/tests/host/test_host_bool_params.yml
index efded1f15a17d9b55340d3c7991db704f5bf1e09..bc35f97e1fd5f28d93dc05319a1f0f25e0db3e5a 100644
--- a/tests/host/test_host_bool_params.yml
+++ b/tests/host/test_host_bool_params.yml
@@ -6,7 +6,7 @@
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Set host1_fqdn .. host6_fqdn
diff --git a/tests/host/test_host_ipaddresses.yml b/tests/host/test_host_ipaddresses.yml
index 45500707d875b3403bf4566de6048ce4d5a0da49..bcca18fc65343e4686d7c80d8dfa4c18f8498fd4 100644
--- a/tests/host/test_host_ipaddresses.yml
+++ b/tests/host/test_host_ipaddresses.yml
@@ -6,7 +6,7 @@
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Set host1_fqdn .. host6_fqdn
diff --git a/tests/host/test_host_managedby_host.yml b/tests/host/test_host_managedby_host.yml
index e6fb9dc65d2de818b0cdb439a89ab6be0aa9290b..d5d367801f62f89c53df227e70ea05d466f025a5 100644
--- a/tests/host/test_host_managedby_host.yml
+++ b/tests/host/test_host_managedby_host.yml
@@ -6,7 +6,7 @@
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Set host1_fqdn .. host2_fqdn
@@ -55,39 +55,39 @@
     register: result
     failed_when: result.changed
 
-  - name: Host "{{ host1_fqdn }}" managed by "{{ groups.ipaserver[0] }}"
+  - name: Host "{{ host1_fqdn }}" managed by "{{ ansible_fqdn }}"
     ipahost:
       ipaadmin_password: SomeADMINpassword
       name: "{{ host1_fqdn }}"
-      managedby_host: "{{ groups.ipaserver[0] }}"
+      managedby_host: "{{ ansible_fqdn }}"
       action: member
     register: result
     failed_when: not result.changed
 
-  - name: Host "{{ host1_fqdn }}" managed by "{{ groups.ipaserver[0] }}" again
+  - name: Host "{{ host1_fqdn }}" managed by "{{ ansible_fqdn }}" again
     ipahost:
       ipaadmin_password: SomeADMINpassword
       name: "{{ host1_fqdn }}"
-      managedby_host: "{{ groups.ipaserver[0] }}"
+      managedby_host: "{{ ansible_fqdn }}"
       action: member
     register: result
     failed_when: result.changed
 
-  - name: Host "{{ host1_fqdn }}" not managed by "{{ groups.ipaserver[0] }}"
+  - name: Host "{{ host1_fqdn }}" not managed by "{{ ansible_fqdn }}"
     ipahost:
       ipaadmin_password: SomeADMINpassword
       name: "{{ host1_fqdn }}"
-      managedby_host: "{{ groups.ipaserver[0] }}"
+      managedby_host: "{{ ansible_fqdn }}"
       action: member
       state: absent
     register: result
     failed_when: not result.changed
 
-  - name: Host "{{ host1_fqdn }}" not managed by "{{ groups.ipaserver[0] }}" again
+  - name: Host "{{ host1_fqdn }}" not managed by "{{ ansible_fqdn }}" again
     ipahost:
       ipaadmin_password: SomeADMINpassword
       name: "{{ host1_fqdn }}"
-      managedby_host: "{{ groups.ipaserver[0] }}"
+      managedby_host: "{{ ansible_fqdn }}"
       action: member
       state: absent
     register: result
diff --git a/tests/host/test_host_no_zone.yml b/tests/host/test_host_no_zone.yml
index be6fe21807e2fe621ced885c95c4a70fed0605f0..629e4baf0841a9cff7c47dccdfbe8e566cd08d5f 100644
--- a/tests/host/test_host_no_zone.yml
+++ b/tests/host/test_host_no_zone.yml
@@ -6,6 +6,7 @@
   tasks:
   - name: Ensure host with inexistent zone is absent.
     ipahost:
+      ipaadmin_password: SomeADMINpassword
       name: host01.absentzone.test
       state: absent
     register: result
diff --git a/tests/host/test_host_principal.yml b/tests/host/test_host_principal.yml
index 6c7d0dc04d3ac241045818c330fa87e0b56ac39f..5bef0522a813b82bfab8b376f48fbab96c33ac33 100644
--- a/tests/host/test_host_principal.yml
+++ b/tests/host/test_host_principal.yml
@@ -6,12 +6,12 @@
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Get Realm from server name
     set_fact:
-      ipaserver_realm: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') | upper }}"
+      ipaserver_realm: "{{ ansible_fqdn.split('.')[1:] | join ('.') | upper }}"
     when: ipaserver_realm is not defined
 
   - name: Set host1_fqdn
diff --git a/tests/host/test_host_random.yml b/tests/host/test_host_random.yml
index 376740c736ae421bd0b8e72dd27768824f4f2983..211d660c9b323f9cf4302be08e1d1e1fe5463f6d 100644
--- a/tests/host/test_host_random.yml
+++ b/tests/host/test_host_random.yml
@@ -6,7 +6,7 @@
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Set host1_fqdn and host2_fqdn
@@ -77,11 +77,11 @@
     debug:
       var: ipahost.host["{{host2_fqdn }}"].randompassword
 
-  - name: Enrolled host "{{ groups.ipaserver[0] }}" fails to set random password with update_password always
+  - name: Enrolled host "{{ ansible_fqdn }}" fails to set random password with update_password always
     ipahost:
       ipaadmin_password: SomeADMINpassword
       hosts:
-      - name: "{{ groups.ipaserver[0] }}"
+      - name: "{{ ansible_fqdn }}"
         random: yes
       update_password: always
     register: ipahost
@@ -89,7 +89,7 @@
 
   - assert:
       that:
-      - ipahost.host["{{ groups.ipaserver[0] }}"].randompassword is
+      - ipahost.host["{{ ansible_fqdn }}"].randompassword is
         not defined
       - "'Password cannot be set on enrolled host' in ipahost.msg"
 
diff --git a/tests/host/test_host_reverse.yml b/tests/host/test_host_reverse.yml
index 9031b70b33aadfd63d130fcea21f2a669d040b01..9a59c489d8582bc1e2286d4b32e20543f6ee4048 100644
--- a/tests/host/test_host_reverse.yml
+++ b/tests/host/test_host_reverse.yml
@@ -2,12 +2,11 @@
 - name: Test host
   hosts: ipaserver
   become: true
-  gather_facts: true
 
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Set host1_fqdn
@@ -26,15 +25,29 @@
     set_fact:
       ipv4_prefix: "{{ ansible_default_ipv4.address.split('.')[:-1] |
                        join('.') }}"
-      reverse_zone: "{{ ansible_default_ipv4.address.split('.')[2::-1] |
-                        join('.') }}"
+
+  - name: Set zone prefixes.
+    set_fact:
+      zone_ipv6_reverse: "ip6.arpa."
+      zone_ipv6_reverse_workaround: "d.f.ip6.arpa."
+      zone_prefix_reverse: "in-addr.arpa"
+      zone_prefix_reverse_8: "{{ ipv4_prefix.split('.')[2::-1] | join ('.') }}.in-addr.arpa"
+      zone_prefix_reverse_16: "{{ ipv4_prefix.split('.')[1::-1] | join ('.') }}.in-addr.arpa"
+      zone_prefix_reverse_24: "{{ ipv4_prefix.split('.')[::-1] | join ('.') }}.in-addr.arpa"
 
   - name: Set zone for reverse address.
-    command: ipa dnszone-add "{{ item }}" --skip-nameserver-check --skip-overlap-check
+    ipadnszone:
+      ipaadmin_password: SomeADMINpassword
+      name: "{{ item }}"
+      skip_nameserver_check: yes
+      skip_overlap_check: yes
     with_items:
-      - "{{ reverse_zone + '.in-addr.arpa.' }}"
-      - 'ip6.arpa.'
-    ignore_errors: yes
+      - "{{ zone_ipv6_reverse }}"
+      - "{{ zone_ipv6_reverse_workaround }}"
+      - "{{ zone_prefix_reverse }}"
+      - "{{ zone_prefix_reverse_8 }}"
+      - "{{ zone_prefix_reverse_16 }}"
+      - "{{ zone_prefix_reverse_24 }}"
 
   - name: Host "{{ host1_fqdn }}" present
     ipahost:
@@ -96,8 +109,15 @@
     register: result
     failed_when: not result.changed
 
-  - name: Set zone for reverse address.
-    command: ipa dnszone-del "{{ item }}"
+  - name: Delete zone for reverse address.
+    ipadnszone:
+      ipaadmin_password: SomeADMINpassword
+      name: "{{ item }}"
+      state: absent
     with_items:
-      - "{{ reverse_zone + '.in-addr.arpa.' }}"
-      - 'ip6.arpa.'
+      - "{{ zone_ipv6_reverse }}"
+      - "{{ zone_ipv6_reverse_workaround }}"
+      - "{{ zone_prefix_reverse }}"
+      - "{{ zone_prefix_reverse_8 }}"
+      - "{{ zone_prefix_reverse_16 }}"
+      - "{{ zone_prefix_reverse_24 }}"
diff --git a/tests/host/test_hosts.yml b/tests/host/test_hosts.yml
index f82cc612ecebf3644ed88063b2995559b7104802..1159e078e6c553ff56c1f45b212f91a2d066d895 100644
--- a/tests/host/test_hosts.yml
+++ b/tests/host/test_hosts.yml
@@ -2,12 +2,11 @@
 - name: Test hosts
   hosts: ipaserver
   become: true
-  gather_facts: false
 
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Set host1_fqdn .. host6_fqdn
diff --git a/tests/host/test_hosts_managedby_host.yml b/tests/host/test_hosts_managedby_host.yml
index bd6452c4905f8bd79abd76a3689164fe2c49c67f..0fc6651fcb774ae607f2d8d4007cabd2ff9417a5 100644
--- a/tests/host/test_hosts_managedby_host.yml
+++ b/tests/host/test_hosts_managedby_host.yml
@@ -6,7 +6,7 @@
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Set host1_fqdn .. host5_fqdn
diff --git a/tests/host/test_hosts_principal.yml b/tests/host/test_hosts_principal.yml
index 3c10966aec1c2206f4c68f66e698bb1007b67e7c..b53c043353edd265f6224bf1d1a9ee902e6c4c83 100644
--- a/tests/host/test_hosts_principal.yml
+++ b/tests/host/test_hosts_principal.yml
@@ -6,12 +6,12 @@
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Get Realm from server name
     set_fact:
-      ipaserver_realm: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') | upper }}"
+      ipaserver_realm: "{{ ansible_fqdn.split('.')[1:] | join ('.') | upper }}"
     when: ipaserver_realm is not defined
 
   - name: Set host1_fqdn .. host2_fqdn
diff --git a/tests/hostgroup/test_hostgroup.yml b/tests/hostgroup/test_hostgroup.yml
index ba449a06031eed69d86ea46093030d2a413b9968..f5af7bbeb18771a03892c8ff6c79573678aaeb1d 100644
--- a/tests/hostgroup/test_hostgroup.yml
+++ b/tests/hostgroup/test_hostgroup.yml
@@ -2,12 +2,12 @@
 - name: Test hostgroup
   hosts: ipaserver
   become: true
-  gather_facts: false
+  gather_facts: true
 
   tasks:
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Ensure host-group databases, mysql-server and oracle-server are absent
diff --git a/tests/service/certificate/test_service_certificate.yml b/tests/service/certificate/test_service_certificate.yml
index 89c46f10e69aecf419e354cd68bc995c54604d4e..3dc24c5b13f4af170300f8f53ec142460de95354 100644
--- a/tests/service/certificate/test_service_certificate.yml
+++ b/tests/service/certificate/test_service_certificate.yml
@@ -29,7 +29,7 @@
   # setup
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Get IPv4 address prefix from server node
diff --git a/tests/service/test_service.yml b/tests/service/test_service.yml
index 25d66c69e5306e764ef47c2959621159ed40246d..78e353f5fe763ced69584c5d87ecbd9f1780dd04 100644
--- a/tests/service/test_service.yml
+++ b/tests/service/test_service.yml
@@ -19,7 +19,7 @@
   # setup
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Set host1, host2 and svc hosts fqdn
@@ -51,13 +51,16 @@
       ipaadmin_password: SomeADMINpassword
       hosts:
           - name: "{{ host1_fqdn }}"
+            ip_address: "{{ ipv4_prefix + '.101' }}"
             force: yes
           - name: "{{ host2_fqdn }}"
+            ip_address: "{{ ipv4_prefix + '.102' }}"
             force: yes
           - name: "{{ svc_fqdn }}"
             ip_address: "{{ ipv4_prefix + '.201' }}"
           - name: svc.ihavenodns.info
             force: yes
+      update_dns: yes
 
   - name: Ensure testing user user01 is present.
     ipauser:
@@ -408,7 +411,7 @@
       - group02
       allow_retrieve_keytab_host:
       - "{{ host1_fqdn }}"
-      - host02.exampl "{{ groups.ipaserver[0] }}"e.com
+      - "{{ host2_fqdn }}"
       allow_retrieve_keytab_hostgroup:
       - hostgroup01
       - hostgroup02
@@ -543,7 +546,7 @@
 
   - name: Ensure SMB service is present.
     ipaservice:
-      ipaadmin_password: MyPassword123
+      ipaadmin_password: SomeADMINpassword
       name: "{{ host1_fqdn }}"
       smb: yes
       netbiosname: SAMBASVC
@@ -552,7 +555,7 @@
 
   - name: Ensure SMB service is again.
     ipaservice:
-      ipaadmin_password: MyPassword123
+      ipaadmin_password: SomeADMINpassword
       name: "{{ host1_fqdn }}"
       smb: yes
       netbiosname: SAMBASVC
@@ -561,7 +564,7 @@
 
   - name: Ensure SMB service is absent.
     ipaservice:
-      ipaadmin_password: MyPassword123
+      ipaadmin_password: SomeADMINpassword
       name: "cifs/{{ host1_fqdn }}"
       state: absent
     register: result
@@ -569,7 +572,7 @@
 
   - name: Ensure SMB service is absent, again.
     ipaservice:
-      ipaadmin_password: MyPassword123
+      ipaadmin_password: SomeADMINpassword
       name: "cifs/{{ host1_fqdn }}"
       state: absent
     register: result
diff --git a/tests/service/test_service_without_skip_host_check.yml b/tests/service/test_service_without_skip_host_check.yml
index 147da0c97d0bd21f1fa4f7def9585a16254cb69a..ce703e9a0d39e1faf7a486b2495e188a38d9380b 100644
--- a/tests/service/test_service_without_skip_host_check.yml
+++ b/tests/service/test_service_without_skip_host_check.yml
@@ -7,7 +7,7 @@
   # setup
   - name: Get Domain from server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
     when: ipaserver_domain is not defined
 
   - name: Set host1, host2 and svc hosts fqdn
@@ -358,7 +358,7 @@
       - group02
       allow_retrieve_keytab_host:
       - "{{ host1_fqdn }}"
-      - host02.exampl "{{ groups.ipaserver[0] }}"e.com
+      - "{{ host2_fqdn }}"
       allow_retrieve_keytab_hostgroup:
       - hostgroup01
       - hostgroup02
diff --git a/tests/sudorule/test_sudorule.yml b/tests/sudorule/test_sudorule.yml
index 81ceca03030f56f5d096a392513ebb6021ec9530..15ba7f460853f881309a6eedf3e530e9382ef782 100644
--- a/tests/sudorule/test_sudorule.yml
+++ b/tests/sudorule/test_sudorule.yml
@@ -3,7 +3,7 @@
 - name: Test sudorule
   hosts: ipaserver
   become: true
-  gather_facts: false
+  gather_facts: true
 
   tasks:
 
@@ -43,8 +43,7 @@
     ipahostgroup:
       ipaadmin_password: SomeADMINpassword
       name: cluster
-      host:
-      - "{{ groups.ipaserver[0] }}"
+      host: "{{ ansible_fqdn }}"
 
   - name: Ensure some sudocmds are available
     ipasudocmd:
@@ -501,20 +500,20 @@
     register: result
     failed_when: result.changed
 
-  - name: Ensure host "{{ groups.ipaserver[0] }}" is present in sudorule.
+  - name: Ensure host "{{ ansible_fqdn }}" is present in sudorule.
     ipasudorule:
       ipaadmin_password: SomeADMINpassword
       name: testrule1
-      host: "{{ groups.ipaserver[0] }}"
+      host: "{{ ansible_fqdn }}"
       action: member
     register: result
     failed_when: not result.changed
 
-  - name: Ensure host "{{ groups.ipaserver[0] }}" is present in sudorule, again.
+  - name: Ensure host "{{ ansible_fqdn }}" is present in sudorule, again.
     ipasudorule:
       ipaadmin_password: SomeADMINpassword
       name: testrule1
-      host: "{{ groups.ipaserver[0] }}"
+      host: "{{ ansible_fqdn }}"
       action: member
     register: result
     failed_when: result.changed
diff --git a/tests/sudorule/test_sudorule_categories.yml b/tests/sudorule/test_sudorule_categories.yml
index e28ca63ce28bf5c5eff9b76efccbcdf393dec78e..a7740c57fdc3138fec085037a3794e3c0577c0e2 100644
--- a/tests/sudorule/test_sudorule_categories.yml
+++ b/tests/sudorule/test_sudorule_categories.yml
@@ -7,7 +7,7 @@
   tasks:
   - name: Get Domain from the server name
     set_fact:
-      ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+      ipaserver_domain: "{{ ansible_fqdn.split('.')[1:] | join ('.') }}"
 
   - name: Ensure sudorules are absent
     ipasudorule:
diff --git a/tests/test_playbook_runs.py b/tests/test_playbook_runs.py
index e44f478516983c7e9c7de59f3afd777db83eba06..86e77be43dcee553b7314dea2a8a1d4e97f17784 100644
--- a/tests/test_playbook_runs.py
+++ b/tests/test_playbook_runs.py
@@ -4,7 +4,7 @@ import os
 import functools
 import tempfile
 
-from subprocess import Popen
+import subprocess
 
 from unittest import TestCase
 
@@ -13,12 +13,53 @@ import pytest
 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
 
 
+def is_docker_env():
+    if os.getenv("RUN_TESTS_IN_DOCKER", "0") == "0":
+        return False
+    return True
+
+
+def get_server_host():
+    return os.getenv("IPA_SERVER_HOST")
+
+
+def get_molecule_scenario():
+    return get_server_host()
+
+
 def get_inventory_content():
-    ipa_server_host = os.getenv("IPA_SERVER_HOST")
-    return "[ipaserver]\n{}".format(ipa_server_host).encode("utf8")
+    ipa_server_host = get_server_host()
+
+    if is_docker_env():
+        ipa_server_host += " ansible_connection=docker"
+
+    lines = [
+        "[ipaserver]",
+        ipa_server_host,
+        "[ipaserver:vars]",
+        "ipaserver_domain=test.local",
+        "ipaserver_realm=TEST.LOCAL",
+    ]
+    return "\n".join(lines).encode("utf8")
 
 
-def run_playbook(playbook):
+def write_logs(result, test_name):
+    log_dir = os.path.join(SCRIPT_DIR, "logs")
+    if not os.path.exists(log_dir):
+        os.makedirs(log_dir)
+
+    # Write stdout log for test
+    log_path = os.path.join(log_dir, test_name + ".log")
+    with open(log_path, "w") as log_file:
+        log_file.write(result.stdout.decode("utf-8"))
+
+    # Write stderr log for test
+    error_log_path = os.path.join(log_dir, test_name + "-error.log")
+    with open(error_log_path, "w") as log_file:
+        log_file.write(result.stderr.decode("utf-8"))
+
+
+def run_playbook(playbook, test_name):
     with tempfile.NamedTemporaryFile() as inventory_file:
         inventory_file.write(get_inventory_content())
         inventory_file.flush()
@@ -28,15 +69,17 @@ def run_playbook(playbook):
             inventory_file.name,
             playbook,
         ]
-        process = Popen(cmd, cwd=SCRIPT_DIR)
-        process.wait()
+        process = subprocess.run(
+            cmd, cwd=SCRIPT_DIR, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+        )
+    write_logs(process, test_name)
 
     return process
 
 
 def list_test_yaml(dir_path):
     yamls = []
-    for yaml_name in os.listdir(dir_path):
+    for yaml_name in sorted(os.listdir(dir_path)):
         if yaml_name.startswith("test_") and yaml_name.endswith(".yml"):
             yamls.append(
                 {
@@ -50,7 +93,7 @@ def list_test_yaml(dir_path):
 def get_test_groups():
     test_dirs = os.listdir(SCRIPT_DIR)
     groups = {}
-    for test_group_dir in test_dirs:
+    for test_group_dir in sorted(test_dirs):
         group_dir_path = os.path.join(SCRIPT_DIR, test_group_dir)
         if not os.path.isdir(group_dir_path):
             continue
@@ -65,6 +108,7 @@ def prepare_test(test_name, test_path):
         @functools.wraps(func)
         def wrapper(*args, **kwargs):
             kwargs["test_path"] = test_path
+            kwargs["test_name"] = test_name
             return func(*args, **kwargs)
 
         return wrapper
@@ -82,13 +126,29 @@ for group_name, group_tests in get_test_groups().items():
         test_path = test_config["path"]
 
         @pytest.mark.skipif(
-            os.getenv("IPA_SERVER_HOST") is None,
+            not get_server_host(),
             reason="Environment variable IPA_SERVER_HOST must be set",
         )
         @prepare_test(test_name, test_path)
-        def method(self, test_path):
-            result = run_playbook(test_path)
-            assert result.returncode == 0
+        def method(self, test_path, test_name):
+            result = run_playbook(test_path, test_name)
+            status_code_msg = "ansible-playbook return code: {}".format(
+                result.returncode
+            )
+            assert_msg = "\n".join(
+                [
+                    "",
+                    "-" * 30 + " Captured stdout " + "-" * 30,
+                    result.stdout.decode("utf8"),
+                    "-" * 30 + " Captured stderr " + "-" * 30,
+                    result.stderr.decode("utf8"),
+                    "-" * 30 + " Playbook Return Code " + "-" * 30,
+                    status_code_msg,
+                ]
+            )
+            # Need to get the last bytes of msg otherwise Azure
+            #   will cut it out.
+            assert result.returncode == 0, assert_msg[-2500:]
 
         _tests[test_name] = method
-    globals()[group_name] = type(group_name, (TestCase,), _tests)
+    globals()[group_name] = type(group_name, tuple([TestCase]), _tests,)
diff --git a/tests/vault/tasks_vault_members.yml b/tests/vault/tasks_vault_members.yml
index 12332ff1897c2a21318e0fc69d0c67faef86ab76..1cbf0473d90eabb17af8f8799a5b90ad361a0c8a 100644
--- a/tests/vault/tasks_vault_members.yml
+++ b/tests/vault/tasks_vault_members.yml
@@ -151,7 +151,7 @@
       ipaadmin_password: SomeADMINpassword
       name: "{{vault.name}}"
       action: member
-      services: "HTTP/{{ groups.ipaserver[0] }}"
+      services: "HTTP/{{ ansible_fqdn }}"
     register: result
     failed_when: not result.changed
 
@@ -160,7 +160,7 @@
       ipaadmin_password: SomeADMINpassword
       name: "{{vault.name}}"
       action: member
-      services: "HTTP/{{ groups.ipaserver[0] }}"
+      services: "HTTP/{{ ansible_fqdn }}"
     register: result
     failed_when: result.changed
 
@@ -169,7 +169,7 @@
       ipaadmin_password: SomeADMINpassword
       name: "{{vault.name}}"
       action: member
-      services: "HTTP/{{ groups.ipaserver[0] }}"
+      services: "HTTP/{{ ansible_fqdn }}"
       state: absent
     register: result
     failed_when: not result.changed
@@ -179,7 +179,7 @@
       ipaadmin_password: SomeADMINpassword
       name: "{{vault.name}}"
       action: member
-      services: "HTTP/{{ groups.ipaserver[0] }}"
+      services: "HTTP/{{ ansible_fqdn }}"
       state: absent
     register: result
     failed_when: result.changed
@@ -264,7 +264,7 @@
     ipavault:
       ipaadmin_password: SomeADMINpassword
       name: "{{vault.name}}"
-      ownerservices: "HTTP/{{ groups.ipaserver[0] }}"
+      ownerservices: "HTTP/{{ ansible_fqdn }}"
       action: member
     register: result
     failed_when: not result.changed
@@ -273,7 +273,7 @@
     ipavault:
       ipaadmin_password: SomeADMINpassword
       name: "{{vault.name}}"
-      ownerservices: "HTTP/{{ groups.ipaserver[0] }}"
+      ownerservices: "HTTP/{{ ansible_fqdn }}"
       action: member
     register: result
     failed_when: result.changed
@@ -282,7 +282,7 @@
     ipavault:
       ipaadmin_password: SomeADMINpassword
       name: "{{vault.name}}"
-      ownerservices: "HTTP/{{ groups.ipaserver[0] }}"
+      ownerservices: "HTTP/{{ ansible_fqdn }}"
       state: absent
       action: member
     register: result
@@ -292,7 +292,7 @@
     ipavault:
       ipaadmin_password: SomeADMINpassword
       name: "{{vault.name}}"
-      ownerservices: "HTTP/{{ groups.ipaserver[0] }}"
+      ownerservices: "HTTP/{{ ansible_fqdn }}"
       state: absent
       action: member
     register: result