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_apm_acl 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            name='foo',
54            acl_order=0,
55            type='static',
56            path_match_case=True,
57            description='foobar',
58            entries=[
59                dict(action='allow',
60                     dst_port='80',
61                     dst_addr='192.168.1.1',
62                     src_port='443',
63                     src_addr='10.10.10.0',
64                     src_mask='255.255.255.128',
65                     protocol='tcp',
66                     host_name='foobar.com',
67                     paths='/shopfront',
68                     scheme='https'
69                     )
70            ]
71        )
72        p = ModuleParameters(params=args)
73        assert p.name == 'foo'
74        assert p.acl_order == 0
75        assert p.type == 'static'
76        assert p.path_match_case == 'true'
77        assert p.description == 'foobar'
78        assert p.entries[0] == dict(action='allow',
79                                    dstEndPort=80,
80                                    dstStartPort=80,
81                                    dstSubnet='192.168.1.1/32',
82                                    srcEndPort=443,
83                                    srcStartPort=443,
84                                    srcSubnet='10.10.10.0/25',
85                                    protocol=6,
86                                    host='foobar.com',
87                                    paths='/shopfront',
88                                    scheme='https'
89                                    )
90
91    def test_api_parameters(self):
92        args = load_fixture('load_apm_acl.json')
93
94        p = ApiParameters(params=args)
95        assert p.name == 'lastone'
96        assert p.acl_order == 2
97        assert p.type == 'static'
98        assert p.path_match_case == 'false'
99        assert p.description == 'foobar'
100        assert p.entries[0] == dict(action='discard',
101                                    dstEndPort=0,
102                                    dstStartPort=0,
103                                    dstSubnet='0.0.0.0/0',
104                                    srcEndPort=0,
105                                    srcStartPort=0,
106                                    srcSubnet='0.0.0.0/0',
107                                    protocol=1,
108                                    scheme='any',
109                                    log='none'
110                                    )
111
112
113class TestManager(unittest.TestCase):
114    def setUp(self):
115        self.spec = ArgumentSpec()
116        self.p1 = patch('ansible_collections.f5networks.f5_modules.plugins.modules.bigip_apm_acl.module_provisioned')
117        self.m1 = self.p1.start()
118        self.m1.return_value = True
119        self.p2 = patch('ansible_collections.f5networks.f5_modules.plugins.modules.bigip_apm_acl.tmos_version')
120        self.p3 = patch('ansible_collections.f5networks.f5_modules.plugins.modules.bigip_apm_acl.send_teem')
121        self.m2 = self.p2.start()
122        self.m2.return_value = '14.1.0'
123        self.m3 = self.p3.start()
124        self.m3.return_value = True
125
126    def tearDown(self):
127        self.p1.stop()
128        self.p2.stop()
129        self.p3.stop()
130
131    def test_create_L4_L7_ACL(self, *args):
132        set_module_args(dict(
133            name='foo',
134            acl_order=0,
135            type='static',
136            path_match_case=True,
137            description='my description',
138            entries=[
139                dict(action='allow',
140                     dst_port='80',
141                     dst_addr='192.168.1.1',
142                     src_port='443',
143                     src_addr='10.10.10.0',
144                     src_mask='255.255.255.128',
145                     protocol='tcp',
146                     host_name='foobar.com',
147                     paths='/shopfront',
148                     scheme='https'
149                     )
150            ],
151            provider=dict(
152                server='localhost',
153                password='password',
154                user='admin'
155            )
156        ))
157
158        module = AnsibleModule(
159            argument_spec=self.spec.argument_spec,
160            supports_check_mode=self.spec.supports_check_mode,
161        )
162
163        # Override methods in the specific type of manager
164        mm = ModuleManager(module=module)
165        mm.exists = Mock(return_value=False)
166        mm.create_on_device = Mock(return_value=True)
167
168        results = mm.exec_module()
169
170        assert results['changed'] is True
171        assert results['acl_order'] == 0
172        assert results['description'] == 'my description'
173        assert results['type'] == 'static'
174        assert results['path_match_case'] == 'yes'
175        assert results['entries'] == [
176            dict(action='allow',
177                 dst_port='80',
178                 dst_addr='192.168.1.1',
179                 src_port='443',
180                 src_addr='10.10.10.0',
181                 src_mask='255.255.255.128',
182                 protocol='tcp',
183                 host_name='foobar.com',
184                 paths='/shopfront',
185                 scheme='https'
186                 )]
187
188    def test_update_L4_L7_ACL(self, *args):
189        set_module_args(dict(
190            name='lastone',
191            acl_order=0,
192            path_match_case='yes',
193            entries=[
194                dict(action='allow',
195                     dst_port='80',
196                     dst_addr='192.168.1.1',
197                     src_port='443',
198                     src_addr='10.10.10.0',
199                     src_mask='255.255.255.128',
200                     protocol='tcp',
201                     host_name='foobar.com',
202                     paths='/shopfront',
203                     scheme='https'
204                     )
205            ],
206            provider=dict(
207                server='localhost',
208                password='password',
209                user='admin'
210            )
211        ))
212
213        current = ApiParameters(params=load_fixture('load_apm_acl.json'))
214
215        module = AnsibleModule(
216            argument_spec=self.spec.argument_spec,
217            supports_check_mode=self.spec.supports_check_mode,
218        )
219
220        # Override methods in the specific type of manager
221        mm = ModuleManager(module=module)
222        mm.exists = Mock(return_value=True)
223        mm.update_on_device = Mock(return_value=True)
224        mm.read_current_from_device = Mock(return_value=current)
225
226        results = mm.exec_module()
227
228        assert results['changed'] is True
229        assert results['acl_order'] == 0
230        assert results['path_match_case'] == 'yes'
231        assert results['entries'] == [
232            dict(action='allow',
233                 dst_port='80',
234                 dst_addr='192.168.1.1',
235                 src_port='443',
236                 src_addr='10.10.10.0',
237                 src_mask='255.255.255.128',
238                 protocol='tcp',
239                 host_name='foobar.com',
240                 paths='/shopfront',
241                 scheme='https'
242                 )]
243