#
# Create and destroy db
#
- name: Create DB
  become_user: postgres
  become: True
  postgresql_db:
    state: present
    name: "{{ db_name }}"
  register: result

- name: assert that module reports the db was created
  assert:
    that:
       - "result.changed == true"
       - "result.db =='{{ db_name }}'"

- name: Check that database created
  become_user: postgres
  become: True
  shell: echo "select datname from pg_database where datname = '{{ db_name }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(1 row)'"

- name: Run create on an already created db
  become_user: postgres
  become: True
  postgresql_db:
    state: present
    name: "{{ db_name }}"
  register: result

- name: assert that module reports the db was unchanged
  assert:
    that:
       - "result.changed == false"

- name: Destroy DB
  become_user: postgres
  become: True
  postgresql_db:
    state: absent
    name: "{{ db_name }}"
  register: result

- name: assert that module reports the db was changed
  assert:
    that:
       - "result.changed == true"

- name: Check that database was destroyed
  become_user: postgres
  become: True
  shell: echo "select datname from pg_database where datname = '{{ db_name }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(0 rows)'"

- name: Destroy DB
  become_user: postgres
  become: True
  postgresql_db:
    state: absent
    name: "{{ db_name }}"
  register: result

- name: assert that removing an alreaady removed db makes no change
  assert:
    that:
       - "result.changed == false"


# This corner case works to add but not to drop.  This is sufficiently crazy
# that I'm not going to attempt to fix it unless someone lets me know that they
# need the functionality
#
#    - postgresql_db:
#        state: 'present'
#        name: '"silly.""name"'
#    - shell: echo "select datname from pg_database where datname = 'silly.""name';" | psql
#      register: result
#
#    - assert:
#        that: "result.stdout_lines[-1] == '(1 row)'"
#    - postgresql_db:
#        state: absent
#        name: '"silly.""name"'
#    - shell: echo "select datname from pg_database where datname = 'silly.""name';" | psql
#      register: result
#
#    - assert:
#        that: "result.stdout_lines[-1] == '(0 rows)'"

#
# Test encoding, collate, ctype, template options
#
- name: Create a DB with encoding, collate, ctype, and template options
  become_user: postgres
  become: True
  postgresql_db:
    name: '{{ db_name }}'
    state: 'present'
    encoding: 'LATIN1'
    lc_collate: 'pt_BR'
    lc_ctype: 'es_MX'
    template: 'template0'

- name: Check that the DB has all of our options
  become_user: postgres
  become: True
  shell: echo "select datname, pg_encoding_to_char(encoding), datcollate, datctype from pg_database where datname = '{{ db_name }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(1 row)'"
      - "'LATIN1' in result.stdout_lines[-2]"
      - "'pt_BR' in result.stdout_lines[-2]"
      - "'es_MX' in result.stdout_lines[-2]"
      - "'UTF8' not in result.stdout_lines[-2]"
      - "'en_US' not in result.stdout_lines[-2]"

- name: Check that running db cration with options a second time does nothing
  become_user: postgres
  become: True
  postgresql_db:
    name: '{{ db_name }}'
    state: 'present'
    encoding: 'LATIN1'
    lc_collate: 'pt_BR'
    lc_ctype: 'es_MX'
    template: 'template0'
  register: result

- assert:
    that:
      - 'result.changed == False'


- name: Check that attempting to change encoding returns an error
  become_user: postgres
  become: True
  postgresql_db:
    name: '{{ db_name }}'
    state: 'present'
    encoding: 'UTF8'
    lc_collate: 'pt_BR'
    lc_ctype: 'es_MX'
    template: 'template0'
  register: result
  ignore_errors: True

- assert:
    that:
      - 'result.failed == True'

- name: Cleanup test DB
  become_user: postgres
  become: True
  postgresql_db:
    name: '{{ db_name }}'
    state: 'absent'

- shell: echo "select datname, pg_encoding_to_char(encoding), datcollate, datctype from pg_database where datname = '{{ db_name }}';" | psql
  become_user: postgres
  become: True
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(0 rows)'"

#
# Create and destroy user
#
- name: Create a user
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    encrypted: 'yes'
    password: "md55c8ccfd9d6711fc69a7eae647fc54f51"
  register: result

- name: Check that ansible reports they were created
  assert:
    that:
      - "result.changed == True"

- name: Check that they were created
  become_user: postgres
  become: True
  shell: echo "select * from pg_user where usename='{{ db_user1 }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(1 row)'"

- name: Check that creating user a second time does nothing
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    encrypted: 'yes'
    password: "md55c8ccfd9d6711fc69a7eae647fc54f51"
  register: result

- name: Check that ansible reports no change
  assert:
    that:
      - "result.changed == False"

- name: Remove user
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    state: 'absent'
  register: result

- name: Check that ansible reports they were removed
  assert:
    that:
      - "result.changed == True"

- name: Check that they were removed
  become_user: postgres
  become: True
  shell: echo "select * from pg_user where usename='{{ db_user1 }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(0 rows)'"

- name: Check that removing user a second time does nothing
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    state: 'absent'
  register: result

- name: Check that ansible reports no change
  assert:
    that:
      - "result.changed == False"

- name: Create a user with all role attributes
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    state: "present"
    role_attr_flags: "SUPERUSER,CREATEROLE,CREATEDB,INHERIT,login"

- name: Check that the user has the requested role attributes
  become_user: postgres
  become: True
  shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin from pg_roles where rolname='{{ db_user1 }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(1 row)'"
      - "'super:t' in result.stdout_lines[-2]"
      - "'createrole:t' in result.stdout_lines[-2]"
      - "'create:t' in result.stdout_lines[-2]"
      - "'inherit:t' in result.stdout_lines[-2]"
      - "'login:t' in result.stdout_lines[-2]"

- name: Modify a user to have no role attributes
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    state: "present"
    role_attr_flags: "NOSUPERUSER,NOCREATEROLE,NOCREATEDB,noinherit,NOLOGIN"
  register: result

- name: Check that ansible reports it modified the role
  assert:
    that:
      - "result.changed == True"

- name: Check that the user has the requested role attributes
  become_user: postgres
  become: True
  shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin from pg_roles where rolname='{{ db_user1 }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(1 row)'"
      - "'super:f' in result.stdout_lines[-2]"
      - "'createrole:f' in result.stdout_lines[-2]"
      - "'create:f' in result.stdout_lines[-2]"
      - "'inherit:f' in result.stdout_lines[-2]"
      - "'login:f' in result.stdout_lines[-2]"

- name: Modify a single role attribute on a user
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    state: "present"
    role_attr_flags: "LOGIN"
  register: result

- name: Check that ansible reports it modified the role
  assert:
    that:
      - "result.changed == True"

- name: Check that the user has the requested role attributes
  become_user: postgres
  become: True
  shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin  from pg_roles where rolname='{{ db_user1 }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(1 row)'"
      - "'super:f' in result.stdout_lines[-2]"
      - "'createrole:f' in result.stdout_lines[-2]"
      - "'create:f' in result.stdout_lines[-2]"
      - "'inherit:f' in result.stdout_lines[-2]"
      - "'login:t' in result.stdout_lines[-2]"

- name: Cleanup the user
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    state: 'absent'

- name: Check that they were removed
  become_user: postgres
  become: True
  shell: echo "select * from pg_user where usename='{{ db_user1 }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(0 rows)'"

### TODO: test expires, fail_on_user

#
# Test db ownership
#
- name: Create an unprivileged user to own a DB
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    encrypted: 'yes'
    password: "md55c8ccfd9d6711fc69a7eae647fc54f51"

- name: Create db with user ownership
  become_user: postgres
  become: True
  postgresql_db:
    name: "{{ db_name }}"
    state: "present"
    owner: "{{ db_user1 }}"

- name: Check that the user owns the newly created DB
  become_user: postgres
  become: True
  shell: echo "select pg_catalog.pg_get_userbyid(datdba) from pg_catalog.pg_database where datname = '{{ db_name }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(1 row)'"
      - "'{{ db_user1 }}' == '{{ result.stdout_lines[-2] | trim }}'"

- name: Change the owner on an existing db
  become_user: postgres
  become: True
  postgresql_db:
    name: "{{ db_name }}"
    state: "present"
    owner: "postgres"
  register: result

- name: assert that ansible says it changed the db
  assert:
    that:
      - "result.changed == True"

- name: Check that the user owns the newly created DB
  become_user: postgres
  become: True
  shell: echo "select pg_catalog.pg_get_userbyid(datdba) from pg_catalog.pg_database where datname = '{{ db_name }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(1 row)'"
      - "'postgres' == '{{ result.stdout_lines[-2] | trim }}'"

- name: Cleanup db
  become_user: postgres
  become: True
  postgresql_db:
    name: "{{ db_name }}"
    state: "absent"

- name: Check that database was destroyed
  become_user: postgres
  become: True
  shell: echo "select datname from pg_database where datname = '{{ db_name }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(0 rows)'"

- name: Cleanup test user
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    state: 'absent'

- name: Check that they were removed
  become_user: postgres
  become: True
  shell: echo "select * from pg_user where usename='{{ db_user1 }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(0 rows)'"

#
# Test settings privleges
#
- name: Create db
  become_user: postgres
  become: True
  postgresql_db:
    name: "{{ db_name }}"
    state: "present"

- name: Create some tables on the db
  become_user: postgres
  become: True
  shell: echo "create table test_table1 (field text);" | psql {{ db_name }}

- become_user: postgres
  become: True
  shell: echo "create table test_table2 (field text);" | psql {{ db_name }}

- name: Create a user with some permissions on the db
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    encrypted: 'yes'
    password: "md55c8ccfd9d6711fc69a7eae647fc54f51"
    db: "{{ db_name }}"
    priv: 'test_table1:INSERT,SELECT,UPDATE,DELETE,TRUNCATE,REFERENCES,TRIGGER/test_table2:INSERT/CREATE,CONNECT,TEMP'

- name: Check that the user has the requested permissions (table1)
  become_user: postgres
  become: True
  shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table1';" | psql {{ db_name }}
  register: result_table1

- name: Check that the user has the requested permissions (table2)
  become_user: postgres
  become: True
  shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2';" | psql {{ db_name }}
  register: result_table2

- name: Check that the user has the requested permissions (database)
  become_user: postgres
  become: True
  shell: echo "select datacl from pg_database where datname='{{ db_name }}';" | psql {{ db_name }}
  register: result_database

- assert:
    that:
      - "result_table1.stdout_lines[-1] == '(7 rows)'"
      - "'INSERT' in result_table1.stdout"
      - "'SELECT' in result_table1.stdout"
      - "'UPDATE' in result_table1.stdout"
      - "'DELETE' in result_table1.stdout"
      - "'TRUNCATE' in result_table1.stdout"
      - "'REFERENCES' in result_table1.stdout"
      - "'TRIGGER' in result_table1.stdout"
      - "result_table2.stdout_lines[-1] == '(1 row)'"
      - "'INSERT' == '{{ result_table2.stdout_lines[-2] | trim }}'"
      - "result_database.stdout_lines[-1] == '(1 row)'"
      - "'{{ db_user1 }}=CTc/postgres' in result_database.stdout_lines[-2]"

- name: Add another permission for the user
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    encrypted: 'yes'
    password: "md55c8ccfd9d6711fc69a7eae647fc54f51"
    db: "{{ db_name }}"
    priv: 'test_table2:select'
  register: results

- name: Check that ansible reports it changed the user
  assert:
    that:
      - "results.changed == True"

- name: Check that the user has the requested permissions (table2)
  become_user: postgres
  become: True
  shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2';" | psql {{ db_name }}
  register: result_table2

- assert:
    that:
      - "result_table2.stdout_lines[-1] == '(2 rows)'"
      - "'INSERT' in result_table2.stdout"
      - "'SELECT' in result_table2.stdout"


#
# Test priv setting via postgresql_privs module
# (Depends on state from previous _user privs tests)
#

- name: Revoke a privilege
  become_user: postgres
  become: True
  postgresql_privs:
    type: "table"
    state: "absent"
    roles: "{{ db_user1 }}"
    privs: "INSERT"
    objs: "test_table2"
    db: "{{ db_name }}"
  register: results

- name: Check that ansible reports it changed the user
  assert:
    that:
      - "results.changed == True"

- name: Check that the user has the requested permissions (table2)
  become_user: postgres
  become: True
  shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2';" | psql {{ db_name }}
  register: result_table2

- assert:
    that:
      - "result_table2.stdout_lines[-1] == '(1 row)'"
      - "'SELECT' == '{{ result_table2.stdout_lines[-2] | trim }}'"

- name: Revoke many privileges on multiple tables
  become_user: postgres
  become: True
  postgresql_privs:
    state: "absent"
    roles: "{{ db_user1 }}"
    privs: "INSERT,select,UPDATE,TRUNCATE,REFERENCES,TRIGGER,delete"
    objs: "test_table2,test_table1"
    db: "{{ db_name }}"
  register: results

- name: Check that ansible reports it changed the user
  assert:
    that:
      - "results.changed == True"

- name: Check that permissions were revoked (table1)
  become_user: postgres
  become: True
  shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table1';" | psql {{ db_name }}
  register: result_table1

- name: Check that permissions were revoked (table2)
  become_user: postgres
  become: True
  shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2';" | psql {{ db_name }}
  register: result_table2

- assert:
    that:
      - "result_table1.stdout_lines[-1] == '(0 rows)'"
      - "result_table2.stdout_lines[-1] == '(0 rows)'"

- name: Revoke database privileges
  become_user: postgres
  become: True
  postgresql_privs:
    type: "database"
    state: "absent"
    roles: "{{ db_user1 }}"
    privs: "Create,connect,TEMP"
    objs: "{{ db_name }}"
    db: "{{ db_name }}"

- name: Check that the user has the requested permissions (database)
  become_user: postgres
  become: True
  shell: echo "select datacl from pg_database where datname='{{ db_name }}';" | psql {{ db_name }}
  register: result_database

- assert:
    that:
      - "result_database.stdout_lines[-1] == '(1 row)'"
      - "'{{ db_user1 }}' not in result_database.stdout"

- name: Grant database privileges
  become_user: postgres
  become: True
  postgresql_privs:
    type: "database"
    state: "present"
    roles: "{{ db_user1 }}"
    privs: "CREATE,connect"
    objs: "{{ db_name }}"
    db: "{{ db_name }}"
  register: results

- name: Check that ansible reports it changed the user
  assert:
    that:
      - "results.changed == True"

- name: Check that the user has the requested permissions (database)
  become_user: postgres
  become: True
  shell: echo "select datacl from pg_database where datname='{{ db_name }}';" | psql {{ db_name }}
  register: result_database

- assert:
    that:
      - "result_database.stdout_lines[-1] == '(1 row)'"
      - "'{{ db_user1 }}=Cc' in result_database.stdout"

- name: Grant a single privilege on a table
  become_user: postgres
  become: True
  postgresql_privs:
    state: "present"
    roles: "{{ db_user1 }}"
    privs: "INSERT"
    objs: "test_table1"
    db: "{{ db_name }}"

- name: Check that permissions were added (table1)
  become_user: postgres
  become: True
  shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table1';" | psql {{ db_name }}
  register: result_table1

- assert:
    that:
      - "result_table1.stdout_lines[-1] == '(1 row)'"
      - "'{{ result_table1.stdout_lines[-2] | trim }}' == 'INSERT'"

- name: Grant many privileges on multiple tables
  become_user: postgres
  become: True
  postgresql_privs:
    state: "present"
    roles: "{{ db_user1 }}"
    privs: 'INSERT,SELECT,UPDATE,DELETE,TRUNCATE,REFERENCES,trigger'
    objs: "test_table2,test_table1"
    db: "{{ db_name }}"

- name: Check that permissions were added (table1)
  become_user: postgres
  become: True
  shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table1';" | psql {{ db_name }}
  register: result_table1

- name: Check that permissions were added (table2)
  become_user: postgres
  become: True
  shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2';" | psql {{ db_name }}
  register: result_table2

- assert:
    that:
      - "result_table1.stdout_lines[-1] == '(7 rows)'"
      - "'INSERT' in result_table1.stdout"
      - "'SELECT' in result_table1.stdout"
      - "'UPDATE' in result_table1.stdout"
      - "'DELETE' in result_table1.stdout"
      - "'TRUNCATE' in result_table1.stdout"
      - "'REFERENCES' in result_table1.stdout"
      - "'TRIGGER' in result_table1.stdout"
      - "result_table2.stdout_lines[-1] == '(7 rows)'"
      - "'INSERT' in result_table2.stdout"
      - "'SELECT' in result_table2.stdout"
      - "'UPDATE' in result_table2.stdout"
      - "'DELETE' in result_table2.stdout"
      - "'TRUNCATE' in result_table2.stdout"
      - "'REFERENCES' in result_table2.stdout"
      - "'TRIGGER' in result_table2.stdout"

#
# Cleanup
#
- name: Cleanup db
  become_user: postgres
  become: True
  postgresql_db:
    name: "{{ db_name }}"
    state: "absent"

- name: Check that database was destroyed
  become_user: postgres
  become: True
  shell: echo "select datname from pg_database where datname = '{{ db_name }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(0 rows)'"

- name: Cleanup test user
  become_user: postgres
  become: True
  postgresql_user:
    name: "{{ db_user1 }}"
    state: 'absent'

- name: Check that they were removed
  become_user: postgres
  become: True
  shell: echo "select * from pg_user where usename='{{ db_user1 }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(0 rows)'"

#
# Test login_user functionality
#
- name: Create a user to test login module parameters
  become: True
  become_user: postgres
  postgresql_user:
    name: "{{ db_user1 }}"
    state: "present"
    encrypted: 'no'
    password: "password"
    role_attr_flags: "CREATEDB,LOGIN,CREATEROLE"

- name: Create db
  postgresql_db:
    name: "{{ db_name }}"
    state: "present"
    login_user: "{{ db_user1 }}"
    login_password: "password"
    login_host: "localhost"

- name: Check that database created
  become: True
  become_user: postgres
  shell: echo "select datname from pg_database where datname = '{{ db_name }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(1 row)'"

- name: Create a user
  postgresql_user:
    name: "{{ db_user2 }}"
    state: "present"
    encrypted: 'yes'
    password: "md55c8ccfd9d6711fc69a7eae647fc54f51"
    db: "{{ db_name }}"
    login_user: "{{ db_user1 }}"
    login_password: "password"
    login_host: "localhost"

- name: Check that they were created
  become: True
  become_user: postgres
  shell: echo "select * from pg_user where usename='{{ db_user2 }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(1 row)'"

- name: Grant database privileges
  postgresql_privs:
    type: "database"
    state: "present"
    roles: "{{ db_user2 }}"
    privs: "CREATE,connect"
    objs: "{{ db_name }}"
    db: "{{ db_name }}"
    login: "{{ db_user1 }}"
    password: "password"
    host: "localhost"

- name: Check that the user has the requested permissions (database)
  become: True
  become_user: postgres
  shell: echo "select datacl from pg_database where datname='{{ db_name }}';" | psql {{ db_name }}
  register: result_database

- assert:
    that:
      - "result_database.stdout_lines[-1] == '(1 row)'"
      - "'{{ db_user2 }}=Cc' in result_database.stdout"

- name: Remove user
  postgresql_user:
    name: "{{ db_user2 }}"
    state: 'absent'
    priv: "ALL"
    db: "{{ db_name }}"
    login_user: "{{ db_user1 }}"
    login_password: "password"
    login_host: "localhost"

- name: Check that they were removed
  become: True
  become_user: postgres
  shell: echo "select * from pg_user where usename='{{ db_user2 }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(0 rows)'"

- name: Destroy DB
  postgresql_db:
    state: absent
    name: "{{ db_name }}"
    login_user: "{{ db_user1 }}"
    login_password: "password"
    login_host: "localhost"

- name: Check that database was destroyed
  become: True
  become_user: postgres
  shell: echo "select datname from pg_database where datname = '{{ db_name }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(0 rows)'"

#
# Cleanup
#
- name: Cleanup test user
  become: True
  become_user: postgres
  postgresql_user:
    name: "{{ db_user1 }}"
    state: 'absent'

- name: Check that they were removed
  become: True
  become_user: postgres
  shell: echo "select * from pg_user where usename='{{ db_user1 }}';" | psql
  register: result

- assert:
    that:
      - "result.stdout_lines[-1] == '(0 rows)'"
