from unittest import TestCase

from paramiko import SSHException

from pyinfra.api import Config, State
from pyinfra.api.connect import connect_all
from pyinfra.api.exceptions import NoGroupError, NoHostError, PyinfraError

from ..paramiko_util import PatchSSHTestCase
from ..util import make_inventory


class TestInventoryApi(TestCase):
    def test_inventory_creation(self):
        inventory = make_inventory()

        # Check length
        assert len(inventory.hosts) == 2

        # Get a host
        host = inventory.get_host('somehost')
        assert host.data.ssh_user == 'vagrant'

        # Check our group data
        assert inventory.get_group_data('test_group') == {
            'group_data': 'hello world',
        }

    def test_tuple_host_group_inventory_creation(self):
        inventory = make_inventory(
            hosts=[
                ('somehost', {'some_data': 'hello'}),
            ],
            tuple_group=([
                ('somehost', {'another_data': 'world'}),
            ], {
                'tuple_group_data': 'word',
            }),
        )

        # Check host data
        host = inventory.get_host('somehost')
        assert host.data.some_data == 'hello'
        assert host.data.another_data == 'world'

        # Check group data
        assert host.data.tuple_group_data == 'word'

    def test_host_and_group_errors(self):
        inventory = make_inventory()

        with self.assertRaises(NoGroupError):
            inventory.get_group('i-dont-exist')


class TestStateApi(PatchSSHTestCase):
    def test_fail_percent(self):
        inventory = make_inventory((
            'somehost',
            ('thinghost', {'ssh_hostname': SSHException}),
            'anotherhost',
        ))
        state = State(inventory, Config(FAIL_PERCENT=1))

        # Ensure we would fail at this point
        with self.assertRaises(PyinfraError) as context:
            connect_all(state)

        assert context.exception.args[0] == 'Over 1% of hosts failed (33%)'

        # Ensure the other two did connect
        assert len(state.active_hosts) == 2

        with self.assertRaises(NoHostError):
            inventory.get_host('i-dont-exist')