#!/usr/bin/python2
# -*- coding: utf-8 -*-

# This file is part of Cockpit.
#
# Copyright (C) 2016 Red Hat, Inc.
#
# Cockpit is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Cockpit is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Cockpit; If not, see <http://www.gnu.org/licenses/>.

import parent
from testlib import *

import os

# The candlepin image has a lot of demo data preloaded
# useful info/commands:
#    Login: doc      password: password
#    org:   snowwhite
#
#    Login: admin    password: admin
#    org:   admin
#
# if you download product files onto the test machine, these will show up as installed products
# local directory: /etc/pki/product
# sample products used in the tests (different subscription results for doc and admin):
# /root/candlepin/generated_certs/6050.pem
# /root/candlepin/generated_certs/88888.pem
#
# to use the candlepin image on a test machine, either add the certificate or
# allow insecure connections (/etc/rhsm/rhsm.conf -> "insecure = 1")
#
# $IP is the ip of the candlepin machine
#
# add an activation key to a pool:
# curl --insecure --request POST --user admin:admin https://$IP:8443/candlepin/activation_keys/ff80808155ca50b10155ca50cd280010/pools/ff80808155ca50b10155ca51f04607e5
# register with: activation key "awesome_os_pool" and org "admin"
# or: subscription-manager register --activationkey awesome_os_pool --org admin --serverurl https://$IP:8443/candlepin
#
# in order to get the right ids for the activation key and pool, see ACTIVATION_KEY_COMMAND and POOL_COMMAND

WAIT_SCRIPT = """
set -ex
for x in $(seq 1 200); do
    if curl --insecure -s https://%(addr)s:8443/candlepin; then
        break
    else
        sleep 1
    fi
done
"""

ACTIVATION_KEY_COMMAND = """curl -s --insecure --request GET --user admin:admin https://localhost:8443/candlepin/activation_keys | python -c "
import sys
import json

data = json.loads(sys.stdin.read())
print [e['id'] for e in data if e['name'] == 'awesome_os_pool' and e['owner']['displayName'] == 'Admin Owner'][0]
"
"""

POOL_COMMAND = """curl -s --insecure --request GET --user admin:admin https://localhost:8443/candlepin/pools | python -c "
import sys
import json

data = json.loads(sys.stdin.read())
print [ e['id'] for e in data if e['owner']['key'] == 'admin' and e['contractNumber'] == '0' and [p for p in e['providedProducts'] if p['productId'] == '88888'] ][0]
"
"""

@skipImage("No subscriptions", "centos-7", "continuous-atomic", "debian-stable", "debian-testing", "fedora-26", "fedora-27", "fedora-i386", "fedora-atomic", "fedora-testing", "ubuntu-1604", "ubuntu-stable")
class TestSubscriptions(MachineCase):
    provision = {
        "0": { "address": "10.111.113.1/20" },
        "candlepin": { "image": "candlepin", "address": "10.111.113.5/20" }
    }

    def setUp(self):
        MachineCase.setUp(self)
        self.candlepin = self.machines['candlepin']

        # wait for candlepin to be active and verify
        self.candlepin.execute("systemctl start tomcat")

        # download product info from the candlepin machine
        product_file_one = os.path.join(self.tmpdir, "6050.pem")
        product_file_two = os.path.join(self.tmpdir, "88888.pem")
        self.candlepin.download("/root/candlepin/generated_certs/6050.pem", product_file_one)
        self.candlepin.download("/root/candlepin/generated_certs/88888.pem", product_file_two)

        # upload product info to the test machine
        m = self.machine
        m.upload([product_file_one, product_file_two], "/etc/pki/product")

        # make sure that rhsm skips certificate checks for the server
        m.execute("sed -i -e 's/insecure = 0/insecure = 1/g' /etc/rhsm/rhsm.conf")

        # Wait for the web service to be accessible
        args = { "addr": "10.111.113.5" }
        m.execute(script=WAIT_SCRIPT % args)

    def testRegister(self):
        b = self.browser

        self.login_and_go("/subscriptions")

        # wait until we can open the registration dialog
        register_button_sel = "button.btn-primary:contains('Register')"
        b.wait_present(register_button_sel)
        b.wait_visible(register_button_sel)
        b.click(register_button_sel)

        b.wait_present("#subscription-register-url")
        b.wait_visible("#subscription-register-url")

        # optionally: check custom url
        b.click("#subscription-register-url button")
        b.wait_visible("#subscription-register-url .dropdown-menu")
        custom_url_selector = "#subscription-register-url a:contains('Custom')"
        b.wait_present(custom_url_selector)
        b.wait_visible(custom_url_selector)
        b.click(custom_url_selector)
        b.wait_not_present("#subscription-register-url.open")

        # enter server and incorrect login data
        b.wait_present("#subscription-register-url-custom")
        b.wait_visible("#subscription-register-url-custom")
        b.set_val("#subscription-register-url-custom", "10.111.113.5:8443/candlepin")
        b.set_val("#subscription-register-username", "doc")
        b.set_val("#subscription-register-password", "wrongpass")

        # try to register
        dialog_register_button_sel = "div.modal-footer .btn-primary"
        b.click(dialog_register_button_sel)

        # wait for message that we used wrong credentials
        b.wait_in_text("body", "Invalid credentials")

        # enter correct login data and try again, old error should disappear
        b.set_val("#subscription-register-password", "password")
        b.click(dialog_register_button_sel)

        b.wait_not_in_text("body", "Invalid credentials")

        # wait for message that we need to specify our org
        b.wait_in_text("body", "'Organization' required to register.")

        # now specify the org
        b.set_val("#subscription-register-org", "admin")

        # use an activation key
        activation_key_id = self.candlepin.execute(ACTIVATION_KEY_COMMAND).strip()
        pool_id = self.candlepin.execute(POOL_COMMAND).strip()
        key_url = "https://localhost:8443/candlepin/activation_keys/{key}/pools/{pool}".format(key=activation_key_id, pool=pool_id)
        self.candlepin.execute("curl -s --insecure --request POST --user admin:admin {url}".format(url=key_url))
        b.set_val("#subscription-register-username", "")
        b.set_val("#subscription-register-password", "")
        b.set_val("#subscription-register-password", "")
        b.set_val("#subscription-register-key", "awesome_os_pool")

        # try to register again
        b.click(dialog_register_button_sel)

        # old error should disappear
        b.wait_not_in_text("body", "'Organization' required to register.")

        # dialog should disappear
        b.wait_not_present(dialog_register_button_sel)

        # make sure this product isn't subscribed
        product_selector = "tr.listing-ct-item:contains('Snowy OS Premium Architecture Bits')"
        b.wait_present(product_selector)
        # expand
        b.click(product_selector)
        details_selector = "tr.listing-ct-panel:contains('Snowy OS Premium Architecture Bits')"
        b.wait_in_text(details_selector, "6050")
        b.wait_in_text(details_selector, "Not Subscribed")
        # collapse again
        b.click(product_selector)

        # find another one that is subscribed
        product_selector = "tr.listing-ct-item:contains('Shared File System Bits')"
        b.wait_present(product_selector)
        # expand
        b.click(product_selector)
        details_selector = "tr.listing-ct-panel:contains('Shared File System Bits')"
        b.wait_in_text(details_selector, "88888")
        b.wait_not_in_text(details_selector, "Not Subscribed")
        # collapse again
        b.click(product_selector)

        # unregister
        unregister_button_sel = "button.btn-primary:contains('Unregister')"
        b.wait_present(unregister_button_sel)
        b.wait_visible(unregister_button_sel)
        b.click(unregister_button_sel)

        # wait until we can register again and open the dialog
        # wait until we can open the registration dialog
        b.wait_present(register_button_sel)
        b.wait_visible(register_button_sel)
        b.click(register_button_sel)

        b.wait_present("#subscription-register-url")
        b.wait_visible("#subscription-register-url")

        # check custom url
        b.click("#subscription-register-url button")
        b.wait_visible("#subscription-register-url .dropdown-menu")
        custom_url_selector = "#subscription-register-url a:contains('Custom')"
        b.wait_present(custom_url_selector)
        b.wait_visible(custom_url_selector)
        b.click(custom_url_selector)
        b.wait_not_present("#subscription-register-url.open")

        # enter server data
        b.wait_present("#subscription-register-url-custom")
        b.wait_visible("#subscription-register-url-custom")
        b.set_val("#subscription-register-url-custom", "10.111.113.5:8443/candlepin")

        # make sure we have an activation key on the target machine
        self.candlepin.execute("curl -s --insecure --request POST --user admin:admin {url}".format(url=key_url))

        # enter key and org
        b.set_val("#subscription-register-key", "awesome_os_pool")
        b.set_val("#subscription-register-org", "admin")
        b.click(dialog_register_button_sel)

        # dialog should disappear
        b.wait_not_present(dialog_register_button_sel)

        # make sure this product isn't subscribed
        product_selector = "tr.listing-ct-item:contains('Snowy OS Premium Architecture Bits')"
        b.wait_present(product_selector)
        # expand
        b.click(product_selector)
        details_selector = "tr.listing-ct-panel:contains('Snowy OS Premium Architecture Bits')"
        b.wait_in_text(details_selector, "6050")
        b.wait_not_in_text(details_selector, "Not Subscribed")
        # collapse again
        b.click(product_selector)

        # now verify with an unprivileged user
        if self.machine.image != "rhel-7-4":
            b.logout()
            self.machine.execute("useradd junior; echo junior:foobar | chpasswd")
            self.login_and_go("/subscriptions", user="junior")
            b.wait_present(".curtains-ct h1")
            b.wait_in_text(".curtains-ct h1", "current user isn't allowed to access system subscription")
            self.allow_authorize_journal_messages()


if __name__ == '__main__':
    test_main()
