---
- name: Test firewall ansible fact
  hosts: all
  become: true
  tasks:
    - name: Test firewall ansible fact
      block:
        - name: Start with default configuration
          include_role:
            name: linux-system-roles.firewall
          vars:
            firewall:
              - previous: replaced

        - name: Get default zone
          command: firewall-offline-cmd --get-default-zone
          changed_when: false
          register: __default_zone

        # Test base fact (no custom settings applied)

        - name: Get default ansible fact
          include_role:
            name: linux-system-roles.firewall
          vars:
            firewall:

        - name: Fail if firewall_config is undefined
          fail:
            msg: Ansible fact firewall_config is not defined
          when: firewall_config is undefined

        - name: Fail if firewall_config custom exists
          fail:
            msg: custom should not exist if there is no custom configuration
          when: "'custom' in firewall_config"

        - name: Fail if firewall_config defaults do not have attributes
          fail:
            msg: default {{ item }} does not have attributes
          when: item | length == 0
          loop: "{{ firewall_config.default | dict2items }}"

        - name: Fail if default zone is not correct
          fail:
            msg: default zone should be {{ __default_zone.stdout }}
          when: firewall_config.default_zone != __default_zone.stdout

        - name: Spot-check default entries and structure
          assert:
            that:
              - '"snmp" in firewall_config.default.helpers'
              - '"echo-request" in firewall_config.default.icmptypes'
              - '"http" in firewall_config.default.services'
              - '"public" in firewall_config.default.zones'

        - name: Save default ansible fact value
          set_fact:
            __previous_firewall_config: "{{ firewall_config }}"
          no_log: true

        # Test fact after adding custom settings

        - name: Modify firewalld configuration
          shell:
            cmd: |
              firewall-offline-cmd --add-service https
              firewall-offline-cmd --new-service custom
          changed_when: false

        - name: Reload firewalld in booted systems
          when: __firewall_is_booted
          command: firewall-cmd --reload
          changed_when: false

        - name: Refetch firewall_config
          include_role:
            name: linux-system-roles.firewall
          vars:
            firewall:

        - name: Fail if firewall_config not changed
          fail:
            msg: >-
              firewall_config was not modified
              after changing firewall settings
          when: firewall_config == __previous_firewall_config

        - name: Fail if config defaults changed
          fail:
            msg: firewall_config defaults changed (should not have)
          when: firewall_config.default != __previous_firewall_config.default

        - name: Fail if custom config unchanged
          fail:
            msg: firewall customs did not change (when they should have)
          when: >-
            'custom' not in firewall_config or
            'zones' not in firewall_config.custom or
            'services' not in firewall_config.custom

        - name: Check the customized services
          assert:
            that:
              - '"https" in firewall_config.default.services'
              - '"https" not in firewall_config.custom.services'
              - '"custom" not in firewall_config.default.services'
              - '"custom" in firewall_config.custom.services'

        - name: Store previous firewall_config
          set_fact:
            __previous_firewall_config: "{{ firewall_config }}"
          no_log: true

        # Test detailed mode

        - name: Get firewall_config with detailed on
          block:
            - name: Run role with detailed on
              include_role:
                name: linux-system-roles.firewall
              vars:
                firewall:
                  detailed: true
          rescue:
            - name: Record role failure
              set_fact:
                __details_failed: true
          always:
            - name: Default to not failed
              set_fact:
                __details_failed: "{{ __details_failed | default(false) }}"

        # offline mode does not currently have details
        - name: Check role failure with details in non-booted mode
          fail:
            msg: "Role with details did not fail in non-booted mode"
          when: not __firewall_is_booted and not __details_failed

        - name: Test details in booted mode
          when: __firewall_is_booted
          block:
            - name: Assert that role succeeded
              assert:
                that: not __details_failed

            - name: Fail if default settings values not dictionaries
              fail:
                msg: >-
                  detailed firewall_config.default not formatted properly -
                  see README.md for expected formatting
              when: item is not mapping
              loop: "{{ firewall_config.default.values() | list }}"

            - name: Fail if custom firewall_config is not its previous value
              fail:
                msg: custom firewall_config changed unexpectedly
              when: firewall_config.custom != __previous_firewall_config.custom

            - name: Fail if default zone differs
              fail:
                msg: default zone should not have changed
              when: firewall_config.default_zone !=
                __previous_firewall_config.default_zone

            - name: Spot-check default entry details and structure
              assert:
                that:
                  - firewall_config.default.helpers.snmp.description is string
                  - '"reachable" in firewall_config.default.icmptypes["echo-request"].description'
                  - '"HTTP" in firewall_config.default.services.http.description'
                  - '"public areas" in firewall_config.default.zones.public.description'

      always:
        - name: Cleanup
          tags:
            - tests::cleanup
          include_role:
            name: linux-system-roles.firewall
          vars:
            firewall:
              previous: replaced
          no_log: true
