---
- name: Registering container name
  set_fact:
    cname: "{{ cname_prefix ~ '-options' }}"
    cname2: "{{ cname_prefix ~ '-options-h1' }}"
- name: Registering container name
  set_fact:
    cnames: "{{ cnames + [cname, cname2] }}"

####################################################################
## published_ports: error handling #################################
####################################################################

- name: published_ports -- non-closing square bracket
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    published_ports:
    - "[::1:2000:3000"
  register: published_ports_1
  ignore_errors: true

- name: published_ports -- forgot square brackets for IPv6
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    published_ports:
    - "::1:2000:3000"
  register: published_ports_2
  ignore_errors: true

- name: published_ports -- disallow hostnames
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    published_ports:
    - "foo:2000:3000"
  register: published_ports_3
  ignore_errors: true

- assert:
    that:
      - published_ports_1 is failed
      - published_ports_1.msg == 'Cannot find closing "]" in input "[::1:2000:3000" for opening "[" at index 1!'
      - published_ports_2 is failed
      - published_ports_2.msg == 'Invalid port description "::1:2000:3000" - expected 1 to 3 colon-separated parts, but got 5. Maybe you forgot to use square brackets ([...]) around an IPv6 address?'
      - published_ports_3 is failed
      - "published_ports_3.msg == 'Bind addresses for published ports must be IPv4 or IPv6 addresses, not hostnames. Use the dig lookup to resolve hostnames. (Found hostname: foo)'"

####################################################################
## published_ports: all ############################################
####################################################################

- name: published_ports -- all
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    exposed_ports:
    - "9001"
    - "9002"
    published_ports:
    - all
    force_kill: yes
  register: published_ports_1

- name: published_ports -- all (idempotency)
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    exposed_ports:
    - "9001"
    - "9002"
    published_ports:
    - all
    force_kill: yes
  register: published_ports_2

- name: published_ports -- all (writing out 'all')
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    exposed_ports:
    - "9001"
    - "9002"
    published_ports:
    - "9001"
    - "9002"
    force_kill: yes
  register: published_ports_3

- name: published_ports -- all (idempotency 2)
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    exposed_ports:
    - "9001"
    - "9002"
    published_ports:
    - "9002"
    - "9001"
    force_kill: yes
  register: published_ports_4

- name: published_ports -- all (switching back to 'all')
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    exposed_ports:
    - "9001"
    - "9002"
    published_ports:
    - all
    force_kill: yes
  register: published_ports_5

- name: published_ports -- all equivalence with publish_all_ports
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    exposed_ports:
      - "9001"
      - "9002"
    publish_all_ports: true
    force_kill: yes
  register: published_ports_6

- name: cleanup
  docker_container:
    name: "{{ cname }}"
    state: absent
    force_kill: yes
  diff: no

- assert:
    that:
    - published_ports_1 is changed
    - published_ports_2 is not changed
    - published_ports_3 is changed
    - published_ports_4 is not changed
    - published_ports_5 is changed
    - published_ports_6 is not changed

####################################################################
## published_ports: port range #####################################
####################################################################

- name: published_ports -- port range
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    exposed_ports:
    - "9001"
    - "9010-9050"
    published_ports:
    - "9001:9001"
    - "9010-9050:9010-9050"
    force_kill: yes
  register: published_ports_1

- name: published_ports -- port range (idempotency)
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    exposed_ports:
    - "9001"
    - "9010-9050"
    published_ports:
    - "9001:9001"
    - "9010-9050:9010-9050"
    force_kill: yes
  register: published_ports_2

- name: published_ports -- port range (different range)
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    exposed_ports:
    - "9001"
    - "9010-9050"
    published_ports:
    - "9001:9001"
    - "9020-9060:9020-9060"
    force_kill: yes
  register: published_ports_3

- name: cleanup
  docker_container:
    name: "{{ cname }}"
    state: absent
    force_kill: yes
  diff: no

- assert:
    that:
    - published_ports_1 is changed
    - published_ports_2 is not changed
    - published_ports_3 is changed

####################################################################
## published_ports: one-element container port range ###############
####################################################################

- name: published_ports -- one-element container port range
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ item }}"
    state: started
    published_ports:
    - "9010-9050:9010"
    force_kill: yes
  loop:
    - '{{ cname }}'
    - '{{ cname2 }}'
  register: published_ports_1

- name: published_ports -- one-element container port range (idempotency)
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ item }}"
    state: started
    published_ports:
    - "9010-9050:9010"
    force_kill: yes
  loop:
    - '{{ cname }}'
    - '{{ cname2 }}'
  register: published_ports_2

- name: published_ports -- one-element container port range (different range)
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ item }}"
    state: started
    published_ports:
    - "9010-9051:9010"
    force_kill: yes
  loop:
    - '{{ cname }}'
    - '{{ cname2 }}'
  register: published_ports_3

- name: cleanup
  docker_container:
    name: "{{ item }}"
    state: absent
    force_kill: yes
  loop:
    - '{{ cname }}'
    - '{{ cname2 }}'
  diff: no

- assert:
    that:
    - published_ports_1 is changed
    - published_ports_2 is not changed
    - published_ports_3 is changed

####################################################################
## published_ports: IPv6 addresses #################################
####################################################################

- name: published_ports -- IPv6
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    published_ports:
    - "[::1]:9001:9001"
    force_kill: yes
  register: published_ports_1

- name: published_ports -- IPv6 (idempotency)
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    published_ports:
    - "[::1]:9001:9001"
    force_kill: yes
  register: published_ports_2

- name: published_ports -- IPv6 (different IP)
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    published_ports:
    - "127.0.0.1:9001:9001"
    force_kill: yes
  register: published_ports_3

- name: published_ports -- IPv6 (hostname)
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    published_ports:
    - "localhost:9001:9001"
    force_kill: yes
  register: published_ports_4
  ignore_errors: yes

- name: cleanup
  docker_container:
    name: "{{ cname }}"
    state: absent
    force_kill: yes
  diff: no

- assert:
    that:
    - published_ports_1 is changed
    - published_ports_2 is not changed
    - published_ports_3 is changed
    - published_ports_4 is failed

####################################################################
## publish_all_ports ###############################################
####################################################################

- set_fact:
    publish_all_ports_test_cases:
      - test_name: no_options
        changed: true
      - test_name: null_to_true
        publish_all_ports_value: true
        changed: true
      - test_name: true_idempotency
        publish_all_ports_value: true
        changed: false
      - test_name: true_to_null
        changed: false
      - test_name: null_to_true_2
        publish_all_ports_value: true
        changed: false
      - test_name: true_to_false
        publish_all_ports_value: false
        changed: true
      - test_name: false_idempotency
        publish_all_ports_value: false
        changed: false
      - test_name: false_to_null
        changed: false
      - test_name: null_with_published_ports
        published_ports_value: &ports
          - "9001:9001"
          - "9010-9050:9010-9050"
        changed: true
      - test_name: null_to_true_with_published_ports
        publish_all_ports_value: true
        published_ports_value: *ports
        changed: true
      - test_name: true_idempotency_with_published_ports
        publish_all_ports_value: true
        published_ports_value: *ports
        changed: false
      - test_name: true_to_null_with_published_ports
        published_ports_value: *ports
        changed: false
      - test_name: null_to_true_2_with_published_ports
        publish_all_ports_value: true
        published_ports_value: *ports
        changed: false
      - test_name: true_to_false_with_published_ports
        publish_all_ports_value: false
        published_ports_value: *ports
        changed: true
      - test_name: false_idempotency_with_published_ports
        publish_all_ports_value: false
        published_ports_value: *ports
        changed: false
      - test_name: false_to_null_with_published_ports
        published_ports_value: *ports
        changed: false

- name: publish_all_ports ({{ test_case.test_name }})
  docker_container:
    image: "{{ docker_test_image_alpine }}"
    command: '/bin/sh -c "sleep 10m"'
    name: "{{ cname }}"
    state: started
    publish_all_ports: "{{ test_case.publish_all_ports_value | default(omit) }}"
    published_ports: "{{ test_case.published_ports_value | default(omit) }}"
    force_kill: yes
  register: publish_all_ports
  loop_control:
    loop_var: test_case
  loop: "{{ publish_all_ports_test_cases }}"

- assert:
    that:
      - publish_all_ports.results[index].changed == test_case.changed
  loop: "{{ publish_all_ports_test_cases }}"
  loop_control:
    index_var: index
    loop_var: test_case