# -*- coding: utf-8 -*-
# vim:fenc=utf-8

# Copyright (C) 2012-2020 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
#
# X2Go Session Broker is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# X2Go Session Broker 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

import unittest
import tempfile
import copy

# Python X2GoBroker modules
import x2gobroker.brokers.inifile_broker as inifile
import x2gobroker.defaults

class TestX2GoBrokerBackendInifile(unittest.TestCase):

    ### TEST SESSION PROFILES: get_profile_ids()

    def test_getprofileids(self):
        inifile_backend = inifile.X2GoBroker(profile_config_file='../../etc/broker/x2gobroker-sessionprofiles.conf')
        _profile_ids = inifile_backend.get_profile_ids()
        self.assertEqual(len(_profile_ids), 3)
        _expected_profile_ids = [ "localhost-kde", "localhost-mate", "localhost-shadow", ]
        for _id in _profile_ids:
            self.assertTrue( ( _id in _expected_profile_ids ) )
        for _id in _expected_profile_ids:
            self.assertTrue( ( _id in _profile_ids ) )

    ### TEST SESSION PROFILES: get_profile() (check that the default key is _not_ present)

    def test_getprofile_defaultkey(self):
        inifile_backend = inifile.X2GoBroker(profile_config_file='../../etc/broker/x2gobroker-sessionprofiles.conf')
        _profile_ids = inifile_backend.get_profile_ids()
        for _profile_id in _profile_ids:
            self.assertTrue( ( 'default' not in list(inifile_backend.get_profile(_profile_id).keys()) ) )

    # TEST COMPLETION OF DEFAULTS FROM CODE IN defaults.py

    def test_getprofilecompletion(self):
        _session_profiles = """
[DEFAULT]
exports =
fullscreen = false
width = 800
height = 600
applications = TERMINAL, WWWBROWSER

[testprofile]
user = foo
command = GNOME

"""
        tf = tempfile.NamedTemporaryFile(mode='w')
        print(_session_profiles, file=tf)
        tf.seek(0)
        inifile_backend = inifile.X2GoBroker(profile_config_file=tf.name)
        _expected_defaults = copy.deepcopy(x2gobroker.defaults.X2GOBROKER_SESSIONPROFILE_DEFAULTS['DEFAULT'])
        for key in list(copy.deepcopy(_expected_defaults).keys()):
            if key.startswith('acl-'):
                del _expected_defaults[key]
        _expected_defaults.update( {
            'exports': '',
            'fullscreen': False,
            'width': 800,
            'height': 600,
            'applications': ['TERMINAL','WWWBROWSER',],
            'user': 'foo',
            'command': 'GNOME',
        } )
        # just testing the directrdp hard-coded defaults
        _expected_defaults.update( {
            'directrdp': False,
        } )
        _expected_profile = copy.deepcopy(_expected_defaults)
        _profile = inifile_backend.get_profile('testprofile')
        for key in list(_expected_profile.keys()):
            self.assertTrue( ( key in list(_profile.keys()) ) )
        for key in list(_profile.keys()):
            self.assertTrue( ( key in list(_expected_profile.keys())  and _profile[key] == _expected_profile[key] ) )

    ### TEST SESSION PROFILES: get_profile_defaults()

    def test_getprofiledefaults(self):
        inifile_backend = inifile.X2GoBroker(profile_config_file='../../etc/broker/x2gobroker-sessionprofiles.conf')
        _profile_defaults = inifile_backend.get_profile_defaults()
        _expected_profile_defaults = copy.deepcopy(x2gobroker.defaults.X2GOBROKER_SESSIONPROFILE_DEFAULTS['DEFAULT'])
        for key in copy.deepcopy(_expected_profile_defaults):
            if key.startswith('acl-'):
                del _expected_profile_defaults[key]
        for _param in _profile_defaults:
            self.assertTrue( ( _param in list(_expected_profile_defaults.keys()) ) )
        for _param in _expected_profile_defaults:
            self.assertTrue( ( _param in list(_profile_defaults.keys()) and _profile_defaults[_param] == _expected_profile_defaults[_param] ) )

    ### TEST SESSION PROFILES: get_profile(profile_id)

    def test_getprofile(self):
        _session_profiles = """
[DEFAULT]
exports =
fullscreen = false
width = 800
height = 600
applications = TERMINAL, WWWBROWSER

[testprofile1]
user = foo
command = GNOME

[testprofile2]
user = bar
command = KDE
fullscreen = true

[testprofile3]
user = bar
command = KDE
fullscreen = true
acl-users-deny = ALL
acl-users-allow = foo,bar
acl-users-order = deny-allow

[testprofile4]
user = bar
command = gnomE
"""
        tf = tempfile.NamedTemporaryFile(mode='w')
        print(_session_profiles, file=tf)
        tf.seek(0)
        inifile_backend = inifile.X2GoBroker(profile_config_file=tf.name)
        _expected_defaults = copy.deepcopy(x2gobroker.defaults.X2GOBROKER_SESSIONPROFILE_DEFAULTS['DEFAULT'])
        for key in list(copy.deepcopy(_expected_defaults).keys()):
            if key.startswith('acl-'):
                del _expected_defaults[key]
        _expected_defaults.update( {
            'exports': '',
            'fullscreen': False,
            'width': 800,
            'height': 600,
            'applications': ['TERMINAL','WWWBROWSER',],
        } )
        _expected_profile1 = copy.deepcopy(_expected_defaults)
        _expected_profile1.update({
            'user': 'foo',
            'command': 'GNOME',
        })
        _expected_profile2 = copy.deepcopy(_expected_defaults)
        _expected_profile2.update({
            'user': 'bar',
            'command': 'KDE',
            'fullscreen': True,
        })
        _expected_profile3 = copy.deepcopy(_expected_defaults)
        _expected_profile3.update({
            'user': 'bar',
            'command': 'KDE',
            'fullscreen': True,
        })
        _expected_profile4 = copy.deepcopy(_expected_defaults)
        _expected_profile4.update({
            'user': 'bar',
            'command': 'gnomE', # mixture of lower and uppercase in get_profile()
        })
        _profile1 = inifile_backend.get_profile('testprofile1')
        for key in list(_expected_profile1.keys()):
            self.assertTrue( ( key in list(_profile1.keys()) ) )
        for key in list(_profile1.keys()):
            self.assertTrue( ( key in list(_expected_profile1.keys())  and _profile1[key] == _expected_profile1[key] ) )

        _profile2 = inifile_backend.get_profile('testprofile2')
        for key in list(_expected_profile2.keys()):
            self.assertTrue( ( key in list(_profile2.keys()) ) )
        for key in list(_profile2.keys()):
            self.assertTrue( ( key in list(_expected_profile2.keys()) ) and ( _profile2[key] == _expected_profile2[key] ) )

        _profile3 = inifile_backend.get_profile('testprofile3')
        for key in list(_expected_profile3.keys()):
            self.assertTrue( ( key in list(_profile3.keys()) ) )
        for key in list(_profile3.keys()):
            self.assertTrue( ( key in list(_expected_profile3.keys()) ) and ( _profile3[key] == _expected_profile3[key] ) )

        _profile4 = inifile_backend.get_profile('testprofile4')
        for key in list(_expected_profile4.keys()):
            self.assertTrue( ( key in list(_profile4.keys()) ) )
        for key in list(_profile4.keys()):
            self.assertTrue( ( key in list(_expected_profile4.keys()) ) and ( _profile4[key] == _expected_profile4[key] ) )

    ### TEST SESSION PROFILES: get_profile_acls(profile_id)

    def test_getprofileacls(self):
        _session_profiles = """
[DEFAULT]
exports =
fullscreen = false
width = 800
height = 600
applications = TERMINAL, WWWBROWSER
acl-clients-deny = ALL
acl-clients-allow = 10.0.0.0/16,10.1.0.0/16,admin-1.intern,admin-2.intern

[testprofile1]
user = foo
command = GNOME

[testprofile2]
user = foo
command = GNOME
acl-clients-deny = 10.0.2.0/24,ALL

[testprofile3]
user = bar
command = KDE
fullscreen = true
acl-users-deny = ALL
acl-users-allow = foo,bar
acl-users-order = deny-allow
"""
        tf = tempfile.NamedTemporaryFile(mode='w')
        print(_session_profiles, file=tf)
        tf.seek(0)
        inifile_backend = inifile.X2GoBroker(profile_config_file=tf.name)
        _expected_acl_defaults = {
            'acl-clients-deny': ['ALL'],
            'acl-clients-allow': ['10.0.0.0/16','10.1.0.0/16','admin-1.intern','admin-2.intern'],
            'acl-any-order': 'deny-allow',
        }
        _expected_acls_profile1 = copy.deepcopy(_expected_acl_defaults)
        _expected_acls_profile2 = copy.deepcopy(_expected_acl_defaults)
        _expected_acls_profile2.update({
            'acl-clients-deny': ['10.0.2.0/24','ALL'],
            'acl-any-order': 'deny-allow',
        })
        _expected_acls_profile3 = copy.deepcopy(_expected_acl_defaults)
        _expected_acls_profile3.update({
            'acl-users-deny': ['ALL'],
            'acl-users-allow': ['foo','bar'],
            'acl-users-order': 'deny-allow',
            'acl-any-order': 'deny-allow',
        })
        _acls_profile1 = inifile_backend.get_profile_acls('testprofile1')
        for key in list(_expected_acls_profile1.keys()):
            self.assertTrue( ( key in list(_acls_profile1.keys()) ) )
        for key in list(_acls_profile1.keys()):
            self.assertTrue( ( key in list(_expected_acls_profile1.keys())  and _acls_profile1[key] == _expected_acls_profile1[key] ) )

        _acls_profile2 = inifile_backend.get_profile_acls('testprofile2')
        for key in list(_expected_acls_profile2.keys()):
            self.assertTrue( ( key in list(_acls_profile2.keys()) ) )
        for key in list(_acls_profile2.keys()):
            self.assertTrue( ( key in list(_expected_acls_profile2.keys()) ) and ( _acls_profile2[key] == _expected_acls_profile2[key] ) )

        _acls_profile3 = inifile_backend.get_profile_acls('testprofile3')
        for key in list(_expected_acls_profile3.keys()):
            self.assertTrue( ( key in list(_acls_profile3.keys()) ) )
        for key in list(_acls_profile3.keys()):
            self.assertTrue( ( key in list(_expected_acls_profile3.keys()) ) and ( _acls_profile3[key] == _expected_acls_profile3[key] ) )

    ### TEST: list_profiles() method

    def test_listprofiles(self):
        username = 'foo'
        _session_profiles = """
[DEFAULT]
exports =
fullscreen = false
width = 800
height = 600
applications = TERMINAL, WWWBROWSER

[testprofile1]
user =
command = GNOME

[testprofile2]
user =
command = XFCE

[testprofile3]
user =
command = KDE
fullscreen = true
"""
        tf = tempfile.NamedTemporaryFile(mode='w')
        print(_session_profiles, file=tf)
        tf.seek(0)
        inifile_backend = inifile.X2GoBroker(profile_config_file=tf.name)
        profile_ids = inifile_backend.get_profile_ids()
        profile_ids.sort()
        list_of_profile_ids = list(inifile_backend.list_profiles(username).keys())
        list_of_profile_ids.sort()
        self.assertEqual(profile_ids, list_of_profile_ids)

    ### TEST: list_profiles() method, check override of rootless param for DESKTOP sessions

    def test_listprofiles_rootlessoverride(self):
        username = 'foo'
        _session_profiles = """
[DEFAULT]
rootless = true
command = TERMINAL

[testprofile1]
user =

[testprofile2]
user =
command = XFCE

[testprofile3]
user =
command = KDE
rootless = false

[testprofile4]
user =
command = gnomE
"""
        tf = tempfile.NamedTemporaryFile(mode='w')
        print(_session_profiles, file=tf)
        tf.seek(0)
        inifile_backend = inifile.X2GoBroker(profile_config_file=tf.name)
        profiles = inifile_backend.list_profiles(username)
        self.assertEqual(profiles['testprofile1']['command'], 'TERMINAL')
        self.assertEqual(profiles['testprofile1']['rootless'], True)
        self.assertEqual(profiles['testprofile2']['command'], 'XFCE')
        self.assertEqual(profiles['testprofile2']['rootless'], False)
        self.assertEqual(profiles['testprofile3']['command'], 'KDE')
        self.assertEqual(profiles['testprofile3']['rootless'], False)
        self.assertEqual(profiles['testprofile4']['command'], 'GNOME') # uppercase!
        self.assertEqual(profiles['testprofile4']['rootless'], False)

    ### TEST: list_profiles() method check acl capability

    def test_listprofileswithacls(self):
        _config_defaults = copy.deepcopy(x2gobroker.defaults.X2GOBROKER_CONFIG_DEFAULTS)
        _config = """
[global]
default-user-db = testsuite
default-group-db = testsuite

[inifile]
enable = true
"""
        tfc = tempfile.NamedTemporaryFile(mode='w')
        print(_config, file=tfc)
        tfc.seek(0)

        _session_profiles = """
[DEFAULT]
exports =
fullscreen = false
width = 800
height = 600
applications = TERMINAL, WWWBROWSER
acl-groups-allow = bees
acl-groups-deny = ALL
acl-groups-order = allow-deny

[testprofile1]
user =
command = GNOME
acl-users-allow = flip
acl-users-order = allow-deny

[testprofile2]
user =
command = XFCE
acl-users-allow = thekla
acl-users-order = allow-deny

[testprofile3]
user =
command = KDE
fullscreen = true
acl-users-deny = willi
acl-users-order = deny-allow
"""
        tfs = tempfile.NamedTemporaryFile(mode='w')
        print(_session_profiles, file=tfs)
        tfs.seek(0)
        inifile_backend = inifile.X2GoBroker(config_file=tfc.name, config_defaults=_config_defaults, profile_config_file=tfs.name)

        username_f = 'flip'
        list_of_profiles = inifile_backend.list_profiles(username_f)
        list_of_profile_ids = list(list_of_profiles.keys())
        list_of_profile_ids.sort()
        self.assertEqual(list_of_profile_ids, ['testprofile1'])
        self.assertEqual(list_of_profiles['testprofile1']['command'], 'GNOME')

        username_m = 'maja'
        list_of_profiles = inifile_backend.list_profiles(username_m)
        list_of_profile_ids = list(list_of_profiles.keys())
        list_of_profile_ids.sort()
        self.assertEqual(list_of_profile_ids, ['testprofile1', 'testprofile2', 'testprofile3'])
        self.assertEqual(list_of_profiles['testprofile1']['command'], 'GNOME')
        self.assertEqual(list_of_profiles['testprofile2']['command'], 'XFCE')
        self.assertEqual(list_of_profiles['testprofile3']['command'], 'KDE')

        username_k = 'kassandra'
        list_of_profiles = inifile_backend.list_profiles(username_k)
        list_of_profile_ids = list(list_of_profiles.keys())
        list_of_profile_ids.sort()
        self.assertEqual(list_of_profile_ids, ['testprofile1', 'testprofile2', 'testprofile3'])
        self.assertEqual(list_of_profiles['testprofile1']['command'], 'GNOME')
        self.assertEqual(list_of_profiles['testprofile2']['command'], 'XFCE')
        self.assertEqual(list_of_profiles['testprofile3']['command'], 'KDE')

        username_t = 'thekla'
        list_of_profiles = inifile_backend.list_profiles(username_t)
        list_of_profile_ids = list(list_of_profiles.keys())
        list_of_profile_ids.sort()
        self.assertEqual(list_of_profile_ids, ['testprofile2'])
        self.assertEqual(list_of_profiles['testprofile2']['command'], 'XFCE')

        username_w = 'willi'
        list_of_profiles = inifile_backend.list_profiles(username_w)
        list_of_profile_ids = list(list_of_profiles.keys())
        list_of_profile_ids.sort()
        self.assertEqual(list_of_profile_ids, ['testprofile1', 'testprofile2'])
        self.assertEqual(list_of_profiles['testprofile1']['command'], 'GNOME')
        self.assertEqual(list_of_profiles['testprofile2']['command'], 'XFCE')

    ### TEST: select_session() method

    def test_sessionselection(self):
        _save_portscan = x2gobroker.utils.portscan
        def _fake_portscan(addr, port=22):
            return True
        x2gobroker.utils.portscan = _fake_portscan

        _config_defaults = copy.deepcopy(x2gobroker.defaults.X2GOBROKER_CONFIG_DEFAULTS)
        _config = """
[global]
default-user-db = testsuite
default-group-db = testsuite

[inifile]
enable = true
"""
        tfc = tempfile.NamedTemporaryFile(mode='w')
        print(_config, file=tfc)
        tfc.seek(0)

        _session_profiles = """
[testprofile1]
name = TEST-1
host = test-1.local

[testprofile2]
name = TEST-2
host = test-2.local

[testprofile3]
name = TEST-3
host = test-3.local
sshport = 44566

[testprofile4]
name = TEST-4
host = test-4 (10.0.2.4)

[testprofile5]
name = TEST-5
host = test-5.local (10.0.2.5)

[testprofile6]
name = TEST-6
host = test-6.local (test-6.extern)

[testprofile7]
name = TEST-7
host = test-7 (-test-6.extern)

"""
        tfs = tempfile.NamedTemporaryFile(mode='w')
        print(_session_profiles, file=tfs)
        tfs.seek(0)
        inifile_backend = inifile.X2GoBroker(config_file=tfc.name, config_defaults=_config_defaults, profile_config_file=tfs.name)
        _expected_result_1 = {
            'server': 'test-1.local',
            'port': 22,
        }
        _expected_result_2 = {
            'server': 'test-2.local',
            'port': 22,
        }
        _expected_result_3 = {
            'server': 'test-3.local',
            'port': 44566,
        }
        _expected_result_4 = {
            'server': '10.0.2.4',
            'port': 22,
        }
        _expected_result_5 = {
            'server': '10.0.2.5',
            'port': 22,
        }
        _expected_result_6 = {
            'server': 'test-6.extern',
            'port': 22,
        }
        _expected_result_7 = {
            'server': 'test-7',
            'port': 22,
        }
        self.assertEqual(inifile_backend.select_session('testprofile1'), _expected_result_1)
        self.assertEqual(inifile_backend.select_session('testprofile2'), _expected_result_2)
        self.assertEqual(inifile_backend.select_session('testprofile3'), _expected_result_3)
        self.assertEqual(inifile_backend.select_session('testprofile4'), _expected_result_4)
        self.assertEqual(inifile_backend.select_session('testprofile5'), _expected_result_5)
        self.assertEqual(inifile_backend.select_session('testprofile6'), _expected_result_6)
        self.assertEqual(inifile_backend.select_session('testprofile7'), _expected_result_7)

        x2gobroker.utils.portscan = _save_portscan

    # TEST MULTI-HOST GET_PROFILE / SELECT_SESSION

    def test_multihost_profiles(self):
        _save_portscan = x2gobroker.utils.portscan
        def _fake_portscan(addr, port=22):
            return True
        x2gobroker.utils.portscan = _fake_portscan

        _session_profiles = """
[DEFAULT]
command = MATE
user = foo

[testprofile1]
host = host1

[testprofile2]
host = host1, host2

[testprofile3]
host = host1.mydomain, host2.mydomain

[testprofile4]
host = host1.mydomain, host2.yourdomain

[testprofile5]
host = host1.mydomain (10.0.2.4), host2.mydomain (10.0.2.5)

[testprofile6]
host = host1.mydomain (10.0.2.4), host2.mydomain (10.0.2.5)
sshport = 23467

[testprofile7]
host = docker-vm-1 (localhost:22001), docker-vm-2 (localhost:22002)

[testprofile8]
host = docker-vm-0 (localhost), docker-vm-1 (localhost:22001), docker-vm-2 (localhost:22002)
sshport = 22000

"""
        tf = tempfile.NamedTemporaryFile(mode='w')
        print(_session_profiles, file=tf)
        tf.seek(0)
        inifile_backend = inifile.X2GoBroker(profile_config_file=tf.name)

        # test "testprofile1"
        _profile1 = inifile_backend.get_profile('testprofile1')
        self.assertTrue( ( _profile1['host'] == ['host1'] ) )
        for key in list(_profile1.keys()):
            self.assertFalse( (key.startswith('host') and key != 'host' ) )
        _session1 = inifile_backend.select_session('testprofile1')
        self.assertEqual ( _session1, {'port': 22, 'server': 'host1'} )

        # test "testprofile2"
        _profile2 = inifile_backend.get_profile('testprofile2')
        _profile2['host'].sort()
        self.assertTrue( ( _profile2['host'] == ['host1', 'host2'] ) )
        for key in list(_profile2.keys()):
            self.assertFalse( (key.startswith('host') and key != 'host' ) )
        _session2 = inifile_backend.select_session('testprofile2')
        self.assertTrue ( _session2['port'] == 22 )
        self.assertTrue ( _session2['server'] in ('host1', 'host2') )

        # test "testprofile3"
        _profile3 = inifile_backend.get_profile('testprofile3')
        _profile3['host'].sort()
        _profile5 = inifile_backend.get_profile('testprofile5')
        self.assertTrue( ( _profile3['host'] == ['host1.mydomain', 'host2.mydomain'] ) )
        for key in list(_profile3.keys()):
            self.assertFalse( (key.startswith('host') and key != 'host' ) )
        _session3 = inifile_backend.select_session('testprofile3')
        self.assertTrue ( _session3['port'] == 22 )
        self.assertTrue ( _session3['server'] in ('host1.mydomain', 'host2.mydomain') )

        # test "testprofile4"
        _profile4 = inifile_backend.get_profile('testprofile4')
        _profile4['host'].sort()
        self.assertTrue( ( _profile4['host'] == ['host1.mydomain', 'host2.yourdomain'] ) )
        for key in list(_profile4.keys()):
            self.assertFalse( (key.startswith('host') and key != 'host' ) )
        _session4 = inifile_backend.select_session('testprofile4')
        self.assertTrue ( _session4['port'] == 22 )
        self.assertTrue ( _session4['server'] in ('host1.mydomain', 'host2.yourdomain') )

        # test "testprofile5"
        _profile5 = inifile_backend.get_profile('testprofile5')
        _profile5['host'].sort()
        self.assertTrue( ( _profile5['host'] == ['host1.mydomain', 'host2.mydomain'] ) )
        self.assertTrue( 'host=host1.mydomain' in _profile5 )
        self.assertTrue( 'host=host2.mydomain' in _profile5 )
        self.assertTrue( _profile5['host=host1.mydomain'] == '10.0.2.4' )
        self.assertTrue( _profile5['host=host2.mydomain'] == '10.0.2.5' )
        self.assertTrue( _profile5['sshport'] == 22 )
        _session5 = inifile_backend.select_session('testprofile5')
        self.assertTrue ( _session5['port'] == 22 )
        self.assertTrue ( _session5['server'] in ('10.0.2.4', '10.0.2.5') )

        # test "testprofile6"
        _profile6 = inifile_backend.get_profile('testprofile6')
        _profile6['host'].sort()
        self.assertTrue( ( _profile6['host'] == ['host1.mydomain', 'host2.mydomain'] ) )
        self.assertTrue( 'host=host1.mydomain' in _profile6 )
        self.assertTrue( 'host=host2.mydomain' in _profile6 )
        self.assertTrue( _profile6['host=host1.mydomain'] == '10.0.2.4' )
        self.assertTrue( _profile6['host=host2.mydomain'] == '10.0.2.5' )
        self.assertTrue( _profile6['sshport'] == 23467 )
        i = 0
        while i < 10:
            _session6 = inifile_backend.select_session('testprofile6')
            self.assertTrue ( _session6['port'] == 23467 )
            self.assertTrue ( _session6['server'] in ('10.0.2.4', '10.0.2.5') )
            i += 1

        # test "testprofile7"
        _profile7 = inifile_backend.get_profile('testprofile7')
        _profile7['host'].sort()
        self.assertTrue( ( _profile7['host'] == ['docker-vm-1', 'docker-vm-2'] ) )
        self.assertTrue( 'host=docker-vm-1' in _profile7 )
        self.assertTrue( 'host=docker-vm-2' in _profile7 )
        self.assertTrue( _profile7['host=docker-vm-1'] == 'localhost' )
        self.assertTrue( _profile7['host=docker-vm-2'] == 'localhost' )
        self.assertTrue( _profile7['sshport'] == 22 )
        self.assertTrue( _profile7['sshport=docker-vm-1'] == 22001 )
        self.assertTrue( _profile7['sshport=docker-vm-2'] == 22002 )
        i = 0
        while i < 10:
            _session7 = inifile_backend.select_session('testprofile7')
            self.assertTrue ( _session7['port'] in (22001, 22002) )
            self.assertTrue ( _session7['server'] == 'localhost' )
            i += 1

        # test "testprofile8"
        _profile8 = inifile_backend.get_profile('testprofile8')
        _profile8['host'].sort()
        self.assertTrue( ( _profile8['host'] == ['docker-vm-0', 'docker-vm-1', 'docker-vm-2'] ) )
        self.assertTrue( 'host=docker-vm-0' in _profile8 )
        self.assertTrue( 'host=docker-vm-1' in _profile8 )
        self.assertTrue( 'host=docker-vm-2' in _profile8 )
        self.assertTrue( _profile8['host=docker-vm-0'] == 'localhost' )
        self.assertTrue( _profile8['host=docker-vm-1'] == 'localhost' )
        self.assertTrue( _profile8['host=docker-vm-2'] == 'localhost' )
        self.assertTrue( _profile8['sshport'] == 22000 )
        self.assertFalse( 'sshport=docker-vm-0' in _profile8 )
        self.assertTrue( _profile8['sshport=docker-vm-1'] == 22001 )
        self.assertTrue( _profile8['sshport=docker-vm-2'] == 22002 )
        i = 0
        while i < 10:
            _session8 = inifile_backend.select_session('testprofile8', username='foo')
            self.assertTrue ( _session8['port'] in (22000, 22001, 22002) )
            self.assertTrue ( _session8['server'] == 'localhost' )
            i += 1

        x2gobroker.utils.portscan = _save_portscan

    def test_multihost_profiles_with_offline_servers(self):
        _save_portscan = x2gobroker.utils.portscan
        def _fake_portscan(addr, port=22):
            if addr == 'host1.mydomain':
                return True
            if addr == 'host2.mydomain':
                return True
            if addr == 'host2.internal':
                return True
            if addr == 'host3.internal':
                return True
            return False
        x2gobroker.utils.portscan = _fake_portscan

        _session_profiles = """
[DEFAULT]
command = MATE
user = foo

[testprofile1]
host = host1.mydomain, host2.mydomain, host3.mydomain
broker-portscan-x2goservers = false
broker-agent-query-mode = NONE

[testprofile2]
host = host1.mydomain, host2.mydomain, host3.mydomain
broker-portscan-x2goservers = true
broker-agent-query-mode = NONE

[testprofile3]
host = host1.internal (host1.external), host2.internal (host2.external), host3.internal (host3.external)

"""
        tf = tempfile.NamedTemporaryFile(mode='w')
        print(_session_profiles, file=tf)
        tf.seek(0)
        inifile_backend = inifile.X2GoBroker(profile_config_file=tf.name)

        i = 0
        selected_hosts = []
        # we assume that in 1000 test steps we will stumble over all three host names
        while i < 1000 or len(selected_hosts) != 3:
            _session1 = inifile_backend.select_session('testprofile1', username='foo')
            self.assertTrue ( _session1['server'] in ('host1.mydomain', 'host2.mydomain', 'host3.mydomain'))
            if _session1['server'] not in selected_hosts:
                selected_hosts.append(_session1['server'])
            i += 1

        self.assertTrue ( len(selected_hosts) == 3 )

        i = 0
        selected_hosts = []
        # we assume that if the code is broken we would receive
        # the down host (host3.mydomain) within 30 test steps at least once
        while i <= 30:
            _session2 = inifile_backend.select_session('testprofile2', username='foo')
            self.assertTrue ( _session2['server'] in ('host1.mydomain', 'host2.mydomain'))
            if _session2['server'] not in selected_hosts:
                selected_hosts.append(_session2['server'])
            i += 1
        self.assertTrue ( len(selected_hosts) == 2 )

        i = 0
        selected_hosts = []
        # we assume that if the code is broken we would receive
        # the down host (host1.mydomain/10.0.2.4) within 30 test steps at least once
        while i <= 30:
            _session3 = inifile_backend.select_session('testprofile3', username='foo')
            self.assertTrue ( _session3['server'] in ('host2.external', 'host3.external'))
            if _session3['server'] not in selected_hosts:
                selected_hosts.append(_session3['server'])
            i += 1
        self.assertTrue ( len(selected_hosts) == 2 )

        x2gobroker.utils.portscan = _save_portscan


def test_suite():
    from unittest import TestSuite, makeSuite
    suite = TestSuite()
    suite.addTest(makeSuite(TestX2GoBrokerBackendInifile))
    return suite

