1# -*- coding: utf-8 -*-
2#
3# Copyright: (c) 2019, F5 Networks Inc.
4# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5
6from __future__ import (absolute_import, division, print_function)
7__metaclass__ = type
8
9import os
10import json
11import pytest
12import sys
13
14if sys.version_info < (2, 7):
15    pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
16
17from ansible.module_utils.basic import AnsibleModule
18from ansible_collections.f5networks.f5_modules.plugins.modules.bigip_asm_dos_application import (
19    ApiParameters, ModuleParameters, ModuleManager, ArgumentSpec
20)
21from ansible_collections.f5networks.f5_modules.tests.unit.modules.utils import set_module_args
22from ansible_collections.f5networks.f5_modules.tests.unit.compat import unittest
23from ansible_collections.f5networks.f5_modules.tests.unit.compat.mock import (
24    Mock, patch
25)
26
27
28fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
29fixture_data = {}
30
31
32def load_fixture(name):
33    path = os.path.join(fixture_path, name)
34
35    if path in fixture_data:
36        return fixture_data[path]
37
38    with open(path) as f:
39        data = f.read()
40
41    try:
42        data = json.loads(data)
43    except Exception:
44        pass
45
46    fixture_data[path] = data
47    return data
48
49
50class TestParameters(unittest.TestCase):
51    def test_module_parameters(self):
52        args = dict(
53            profile='dos_foo',
54            geolocations=dict(
55                blacklist=['Argentina', 'Montenegro'],
56                whitelist=['France', 'Belgium']
57            ),
58            heavy_urls=dict(
59                auto_detect=True,
60                latency_threshold=3000,
61                exclude=['/exclude1.html', '/exclude2.html'],
62                include=[dict(url='include1.html', threshold='auto'),
63                         dict(url='include2.html', threshold='2000')],
64            ),
65            mobile_detection=dict(
66                enabled=True,
67                allow_android_rooted_device=True,
68                allow_any_android_package=True,
69                allow_any_ios_package=True,
70                allow_jailbroken_devices=True,
71                allow_emulators=True,
72                client_side_challenge_mode='cshui',
73                ios_allowed_package_names=['foo', 'bar'],
74                android_publishers=['cert1.crt', 'cert2.crt']
75            ),
76            rtbh_duration=180,
77            rtbh_enable=True,
78            scrubbing_duration=360,
79            scrubbing_enable=True,
80            single_page_application=True,
81            trigger_irule=False,
82            partition='Common'
83        )
84
85        p = ModuleParameters(params=args)
86        assert p.profile == 'dos_foo'
87        assert p.geo_whitelist == ['France', 'Belgium']
88        assert p.geo_blacklist == ['Argentina', 'Montenegro']
89        assert p.auto_detect == 'enabled'
90        assert p.latency_threshold == 3000
91        assert p.hw_url_exclude == ['/exclude1.html', '/exclude2.html']
92        assert dict(name='URL/include1.html', threshold='auto', url='/include1.html') in p.hw_url_include
93        assert dict(name='URL/include2.html', threshold='2000', url='/include2.html') in p.hw_url_include
94        assert p.allow_android_rooted_device == 'true'
95        assert p.enable_mobile_detection == 'enabled'
96        assert p.allow_any_android_package == 'true'
97        assert p.allow_any_ios_package == 'true'
98        assert p.allow_jailbroken_devices == 'true'
99        assert p.allow_emulators == 'true'
100        assert p.client_side_challenge_mode == 'cshui'
101        assert p.ios_allowed_package_names == ['foo', 'bar']
102        assert p.android_publishers == ['/Common/cert1.crt', '/Common/cert2.crt']
103        assert p.rtbh_duration == 180
104        assert p.rtbh_enable == 'enabled'
105        assert p.scrubbing_duration == 360
106        assert p.scrubbing_enable == 'enabled'
107        assert p.single_page_application == 'enabled'
108        assert p.trigger_irule == 'disabled'
109
110    def test_api_parameters(self):
111        args = load_fixture('load_asm_dos.json')
112
113        p = ApiParameters(params=args)
114        assert p.geo_whitelist == ['Aland Islands']
115        assert p.geo_blacklist == ['Afghanistan']
116        assert p.auto_detect == 'enabled'
117        assert p.latency_threshold == 1000
118        assert p.hw_url_exclude == ['/exclude.html']
119        assert dict(name='URL/test.htm', threshold='auto', url='/test.htm') in p.hw_url_include
120        assert dict(name='URL/testy.htm', threshold='auto', url='/testy.htm') in p.hw_url_include
121        assert p.allow_android_rooted_device == 'false'
122        assert p.enable_mobile_detection == 'disabled'
123        assert p.allow_any_android_package == 'false'
124        assert p.allow_any_ios_package == 'false'
125        assert p.allow_jailbroken_devices == 'true'
126        assert p.allow_emulators == 'true'
127        assert p.client_side_challenge_mode == 'pass'
128        assert p.ios_allowed_package_names == ['foobarapp']
129        assert p.android_publishers == ['/Common/ca-bundle.crt']
130        assert p.rtbh_duration == 300
131        assert p.rtbh_enable == 'enabled'
132        assert p.scrubbing_duration == 60
133        assert p.scrubbing_enable == 'enabled'
134        assert p.single_page_application == 'enabled'
135        assert p.trigger_irule == 'enabled'
136
137
138class TestManager(unittest.TestCase):
139    def setUp(self):
140        self.spec = ArgumentSpec()
141        self.p1 = patch('ansible_collections.f5networks.f5_modules.plugins.modules.bigip_asm_dos_application.module_provisioned')
142        self.m1 = self.p1.start()
143        self.m1.return_value = True
144        self.p2 = patch('ansible_collections.f5networks.f5_modules.plugins.modules.bigip_asm_dos_application.tmos_version')
145        self.p3 = patch('ansible_collections.f5networks.f5_modules.plugins.modules.bigip_asm_dos_application.send_teem')
146        self.m2 = self.p2.start()
147        self.m2.return_value = '14.1.0'
148        self.m3 = self.p3.start()
149        self.m3.return_value = True
150
151    def tearDown(self):
152        self.p1.stop()
153        self.p2.stop()
154        self.p3.stop()
155
156    def test_create_asm_dos_profile(self, *args):
157        set_module_args(dict(
158            profile='dos_foo',
159            geolocations=dict(
160                blacklist=['Argentina', 'Montenegro'],
161                whitelist=['France', 'Belgium']
162            ),
163            heavy_urls=dict(
164                auto_detect=True,
165                latency_threshold=3000,
166                exclude=['/exclude1.html', '/exclude2.html'],
167                include=[dict(url='include1.html', threshold='auto'),
168                         dict(url='include2.html', threshold='2000')]
169            ),
170            mobile_detection=dict(
171                enabled=True,
172                allow_android_rooted_device=True,
173                allow_any_android_package=True,
174                allow_any_ios_package=True,
175                allow_jailbroken_devices=True,
176                allow_emulators=True,
177                client_side_challenge_mode='cshui',
178                ios_allowed_package_names=['foo', 'bar'],
179                android_publishers=['cert1.crt', 'cert2.crt']
180            ),
181            rtbh_duration=180,
182            rtbh_enable=True,
183            scrubbing_duration=360,
184            scrubbing_enable=True,
185            single_page_application=True,
186            trigger_irule=False,
187            partition='Common',
188            provider=dict(
189                server='localhost',
190                password='password',
191                user='admin'
192            )
193        ))
194
195        module = AnsibleModule(
196            argument_spec=self.spec.argument_spec,
197            supports_check_mode=self.spec.supports_check_mode,
198        )
199
200        # Override methods in the specific type of manager
201        mm = ModuleManager(module=module)
202        mm.exists = Mock(return_value=False)
203        mm.create_on_device = Mock(return_value=True)
204        mm.version_less_than_13_1 = Mock(return_value=False)
205
206        results = mm.exec_module()
207
208        assert results['changed'] is True
209        assert results['geolocations'] == dict(blacklist=['Argentina', 'Montenegro'], whitelist=['France', 'Belgium'])
210        assert results['heavy_urls'] == dict(auto_detect='yes', latency_threshold=3000,
211                                             exclude=['/exclude1.html', '/exclude2.html'],
212                                             include=[dict(url='/include1.html', threshold='auto'),
213                                                      dict(url='/include2.html', threshold='2000')]
214                                             )
215        assert results['mobile_detection'] == dict(enabled='yes', allow_android_rooted_device='yes',
216                                                   allow_any_android_package='yes', allow_any_ios_package='yes',
217                                                   allow_jailbroken_devices='yes', allow_emulators='yes',
218                                                   client_side_challenge_mode='cshui',
219                                                   ios_allowed_package_names=['foo', 'bar'],
220                                                   android_publishers=['/Common/cert1.crt', '/Common/cert2.crt']
221                                                   )
222        assert results['rtbh_duration'] == 180
223        assert results['rtbh_enable'] == 'yes'
224        assert results['scrubbing_duration'] == 360
225        assert results['scrubbing_enable'] == 'yes'
226        assert results['single_page_application'] == 'yes'
227        assert results['trigger_irule'] == 'no'
228
229    def test_update_asm_dos_profile(self, *args):
230        set_module_args(dict(
231            profile='test',
232            heavy_urls=dict(
233                latency_threshold=3000,
234                exclude=['/exclude1.html', '/exclude2.html'],
235                include=[dict(url='include1.html', threshold='auto'),
236                         dict(url='include2.html', threshold='2000')]
237            ),
238            provider=dict(
239                server='localhost',
240                password='password',
241                user='admin'
242            )
243        ))
244
245        current = ApiParameters(params=load_fixture('load_asm_dos.json'))
246
247        module = AnsibleModule(
248            argument_spec=self.spec.argument_spec,
249            supports_check_mode=self.spec.supports_check_mode,
250        )
251
252        # Override methods in the specific type of manager
253        mm = ModuleManager(module=module)
254        mm.exists = Mock(return_value=True)
255        mm.update_on_device = Mock(return_value=True)
256        mm.read_current_from_device = Mock(return_value=current)
257        mm.version_less_than_13_1 = Mock(return_value=False)
258
259        results = mm.exec_module()
260
261        assert results['changed'] is True
262        assert results['heavy_urls'] == dict(latency_threshold=3000, exclude=['/exclude1.html', '/exclude2.html'],
263                                             include=[dict(url='/include1.html', threshold='auto'),
264                                                      dict(url='/include2.html', threshold='2000')]
265                                             )
266