1# -*- coding: utf-8 -*-
2#
3# Copyright (c) 2017 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
18
19try:
20    from library.modules.bigip_user import Parameters
21    from library.modules.bigip_user import ModuleManager
22    from library.modules.bigip_user import ArgumentSpec
23    from library.modules.bigip_user import UnpartitionedManager
24    from library.modules.bigip_user import PartitionedManager
25
26    from library.module_utils.network.f5.common import F5ModuleError
27
28    # In Ansible 2.8, Ansible changed import paths.
29    from test.units.compat import unittest
30    from test.units.compat.mock import Mock
31
32    from test.units.modules.utils import set_module_args
33except ImportError:
34    from ansible.modules.network.f5.bigip_user import Parameters
35    from ansible.modules.network.f5.bigip_user import ModuleManager
36    from ansible.modules.network.f5.bigip_user import ArgumentSpec
37    from ansible.modules.network.f5.bigip_user import UnpartitionedManager
38    from ansible.modules.network.f5.bigip_user import PartitionedManager
39
40    from ansible.module_utils.network.f5.common import F5ModuleError
41
42    # Ansible 2.8 imports
43    from units.compat import unittest
44    from units.compat.mock import Mock
45
46    from units.modules.utils import set_module_args
47
48
49fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
50fixture_data = {}
51
52
53def load_fixture(name):
54    path = os.path.join(fixture_path, name)
55
56    if path in fixture_data:
57        return fixture_data[path]
58
59    with open(path) as f:
60        data = f.read()
61
62    try:
63        data = json.loads(data)
64    except Exception:
65        pass
66
67    fixture_data[path] = data
68    return data
69
70
71class TestParameters(unittest.TestCase):
72    def test_module_parameters(self):
73        access = [{'name': 'Common', 'role': 'guest'}]
74        args = dict(
75            username_credential='someuser',
76            password_credential='testpass',
77            full_name='Fake Person',
78            partition_access=access,
79            update_password='always'
80        )
81
82        p = Parameters(params=args)
83        assert p.username_credential == 'someuser'
84        assert p.password_credential == 'testpass'
85        assert p.full_name == 'Fake Person'
86        assert p.partition_access == access
87        assert p.update_password == 'always'
88
89    def test_api_parameters(self):
90        access = [{'name': 'Common', 'role': 'guest'}]
91        args = dict(
92            name='someuser',
93            description='Fake Person',
94            partitionAccess=access,
95            shell='none'
96        )
97
98        p = Parameters(params=args)
99        assert p.name == 'someuser'
100        assert p.full_name == 'Fake Person'
101        assert p.partition_access == access
102        assert p.shell == 'none'
103
104
105class TestManager(unittest.TestCase):
106
107    def setUp(self):
108        self.spec = ArgumentSpec()
109
110    def test_create_user(self, *args):
111        access = [{'name': 'Common', 'role': 'guest'}]
112        set_module_args(dict(
113            username_credential='someuser',
114            password_credential='testpass',
115            partition_access=access,
116            update_password='on_create',
117            provider=dict(
118                server='localhost',
119                password='password',
120                user='admin'
121            )
122        ))
123
124        module = AnsibleModule(
125            argument_spec=self.spec.argument_spec,
126            supports_check_mode=self.spec.supports_check_mode
127        )
128
129        # Override methods to force specific logic in the module to happen
130        pm = PartitionedManager(module=module, params=module.params)
131        pm.create_on_device = Mock(return_value=True)
132        pm.exists = Mock(return_value=False)
133
134        mm = ModuleManager(module=module)
135        mm.is_version_less_than_13 = Mock(return_value=False)
136        mm.get_manager = Mock(return_value=pm)
137
138        results = mm.exec_module()
139
140        assert results['changed'] is True
141        assert results['partition_access'] == access
142
143    def test_create_user_no_password(self, *args):
144        access = [{'name': 'Common', 'role': 'guest'}]
145        set_module_args(dict(
146            username_credential='someuser',
147            partition_access=access,
148            provider=dict(
149                server='localhost',
150                password='password',
151                user='admin'
152            )
153        ))
154
155        module = AnsibleModule(
156            argument_spec=self.spec.argument_spec,
157            supports_check_mode=self.spec.supports_check_mode
158        )
159
160        # Override methods to force specific logic in the module to happen
161        pm = PartitionedManager(module=module, params=module.params)
162        pm.create_on_device = Mock(return_value=True)
163        pm.exists = Mock(return_value=False)
164
165        mm = ModuleManager(module=module)
166        mm.is_version_less_than_13 = Mock(return_value=False)
167        mm.get_manager = Mock(return_value=pm)
168
169        results = mm.exec_module()
170
171        assert results['changed'] is True
172        assert results['partition_access'] == access
173
174    def test_create_user_partition_access_raises(self, *args):
175        set_module_args(dict(
176            username_credential='someuser',
177            provider=dict(
178                server='localhost',
179                password='password',
180                user='admin'
181            )
182        ))
183
184        module = AnsibleModule(
185            argument_spec=self.spec.argument_spec,
186            supports_check_mode=self.spec.supports_check_mode
187        )
188
189        # Override methods to force specific logic in the module to happen
190        pm = PartitionedManager(module=module, params=module.params)
191        pm.create_on_device = Mock(return_value=True)
192        pm.exists = Mock(return_value=False)
193
194        mm = ModuleManager(module=module)
195        mm.is_version_less_than_13 = Mock(return_value=False)
196        mm.get_manager = Mock(return_value=pm)
197
198        msg = "The 'partition_access' option " \
199              "is required when creating a resource."
200
201        with pytest.raises(F5ModuleError) as ex:
202            mm.exec_module()
203        assert str(ex.value) == msg
204
205    def test_create_user_shell_bash(self, *args):
206        access = [{'name': 'all', 'role': 'admin'}]
207        set_module_args(dict(
208            username_credential='someuser',
209            password_credential='testpass',
210            partition_access=access,
211            update_password='on_create',
212            shell='bash',
213            provider=dict(
214                server='localhost',
215                password='password',
216                user='admin'
217            )
218        ))
219
220        module = AnsibleModule(
221            argument_spec=self.spec.argument_spec,
222            supports_check_mode=self.spec.supports_check_mode
223        )
224
225        # Override methods to force specific logic in the module to happen
226        pm = PartitionedManager(module=module, params=module.params)
227        pm.create_on_device = Mock(return_value=True)
228        pm.exists = Mock(return_value=False)
229
230        mm = ModuleManager(module=module)
231        mm.is_version_less_than_13 = Mock(return_value=False)
232        mm.get_manager = Mock(return_value=pm)
233
234        results = mm.exec_module()
235
236        assert results['changed'] is True
237        assert results['partition_access'] == access
238
239    def test_create_user_shell_not_permitted_raises(self, *args):
240        access = [{'name': 'Common', 'role': 'guest'}]
241        set_module_args(dict(
242            username_credential='someuser',
243            password_credential='testpass',
244            partition_access=access,
245            update_password='on_create',
246            shell='bash',
247            provider=dict(
248                server='localhost',
249                password='password',
250                user='admin'
251            )
252        ))
253
254        module = AnsibleModule(
255            argument_spec=self.spec.argument_spec,
256            supports_check_mode=self.spec.supports_check_mode
257        )
258
259        # Override methods to force specific logic in the module to happen
260        pm = PartitionedManager(module=module, params=module.params)
261        pm.create_on_device = Mock(return_value=True)
262        pm.exists = Mock(return_value=False)
263
264        mm = ModuleManager(module=module)
265        mm.is_version_less_than_13 = Mock(return_value=False)
266        mm.get_manager = Mock(return_value=pm)
267
268        msg = "Shell access is only available to 'admin' or " \
269              "'resource-admin' roles."
270
271        with pytest.raises(F5ModuleError) as ex:
272            mm.exec_module()
273        assert str(ex.value) == msg
274
275    def test_update_user_password_no_pass(self, *args):
276        set_module_args(dict(
277            username_credential='someuser',
278            password_credential='testpass',
279            provider=dict(
280                server='localhost',
281                password='password',
282                user='admin'
283            )
284        ))
285
286        module = AnsibleModule(
287            argument_spec=self.spec.argument_spec,
288            supports_check_mode=self.spec.supports_check_mode
289        )
290
291        # Configure the parameters that would be returned by querying the
292        # remote device
293        current = Parameters(params=load_fixture('load_auth_user_no_pass.json'))
294
295        # Override methods to force specific logic in the module to happen
296        pm = PartitionedManager(module=module, params=module.params)
297        pm.exists = Mock(return_value=True)
298        pm.update_on_device = Mock(return_value=True)
299        pm.read_current_from_device = Mock(return_value=current)
300
301        mm = ModuleManager(module=module)
302        mm.is_version_less_than_13 = Mock(return_value=False)
303        mm.get_manager = Mock(return_value=pm)
304
305        results = mm.exec_module()
306
307        assert results['changed'] is True
308
309    def test_update_user_password_with_pass(self, *args):
310        set_module_args(dict(
311            username_credential='someuser',
312            password_credential='testpass',
313            provider=dict(
314                server='localhost',
315                password='password',
316                user='admin'
317            )
318        ))
319
320        module = AnsibleModule(
321            argument_spec=self.spec.argument_spec,
322            supports_check_mode=self.spec.supports_check_mode
323        )
324
325        # Configure the parameters that would be returned by querying the
326        # remote device
327        current = Parameters(params=load_fixture('load_auth_user_with_pass.json'))
328
329        # Override methods to force specific logic in the module to happen
330        pm = PartitionedManager(module=module, params=module.params)
331        pm.exists = Mock(return_value=True)
332        pm.update_on_device = Mock(return_value=True)
333        pm.read_current_from_device = Mock(return_value=current)
334
335        mm = ModuleManager(module=module)
336        mm.is_version_less_than_13 = Mock(return_value=False)
337        mm.get_manager = Mock(return_value=pm)
338
339        results = mm.exec_module()
340
341        assert results['changed'] is True
342
343    def test_update_user_shell_to_none(self, *args):
344        set_module_args(dict(
345            username_credential='someuser',
346            shell='none',
347            provider=dict(
348                server='localhost',
349                password='password',
350                user='admin'
351            )
352        ))
353
354        module = AnsibleModule(
355            argument_spec=self.spec.argument_spec,
356            supports_check_mode=self.spec.supports_check_mode
357        )
358
359        # Configure the parameters that would be returned by querying the
360        # remote device
361        current = Parameters(
362            params=dict(
363                user='admin',
364                shell='tmsh'
365            )
366        )
367
368        # Override methods to force specific logic in the module to happen
369        pm = PartitionedManager(module=module, params=module.params)
370        pm.exists = Mock(return_value=True)
371        pm.update_on_device = Mock(return_value=True)
372        pm.read_current_from_device = Mock(return_value=current)
373
374        mm = ModuleManager(module=module)
375        mm.is_version_less_than_13 = Mock(return_value=False)
376        mm.get_manager = Mock(return_value=pm)
377
378        results = mm.exec_module()
379
380        assert results['changed'] is True
381        assert results['shell'] == 'none'
382
383    def test_update_user_shell_to_none_shell_attribute_missing(self, *args):
384        set_module_args(dict(
385            username_credential='someuser',
386            shell='none',
387            provider=dict(
388                server='localhost',
389                password='password',
390                user='admin'
391            )
392        ))
393
394        module = AnsibleModule(
395            argument_spec=self.spec.argument_spec,
396            supports_check_mode=self.spec.supports_check_mode
397        )
398
399        # Configure the parameters that would be returned by querying the
400        # remote device
401        access = [{'name': 'Common', 'role': 'guest'}]
402        current = Parameters(
403            params=dict(
404                user='admin',
405                partition_access=access
406            )
407        )
408
409        # Override methods to force specific logic in the module to happen
410        pm = PartitionedManager(module=module, params=module.params)
411        pm.exists = Mock(return_value=True)
412        pm.update_on_device = Mock(return_value=True)
413        pm.read_current_from_device = Mock(return_value=current)
414
415        mm = ModuleManager(module=module)
416        mm.is_version_less_than_13 = Mock(return_value=False)
417        mm.get_manager = Mock(return_value=pm)
418
419        results = mm.exec_module()
420
421        assert results['changed'] is False
422        assert not hasattr(results, 'shell')
423
424    def test_update_user_shell_to_bash(self, *args):
425        set_module_args(dict(
426            username_credential='someuser',
427            shell='bash',
428            provider=dict(
429                server='localhost',
430                password='password',
431                user='admin'
432            )
433        ))
434
435        module = AnsibleModule(
436            argument_spec=self.spec.argument_spec,
437            supports_check_mode=self.spec.supports_check_mode
438        )
439
440        # Configure the parameters that would be returned by querying the
441        # remote device
442        access = [{'name': 'all', 'role': 'admin'}]
443        current = Parameters(
444            params=dict(
445                user='admin',
446                shell='tmsh',
447                partition_access=access
448            )
449        )
450
451        # Override methods to force specific logic in the module to happen
452        upm = UnpartitionedManager(module=module, params=module.params)
453        upm.exists = Mock(return_value=True)
454        upm.update_on_device = Mock(return_value=True)
455        upm.read_current_from_device = Mock(return_value=current)
456
457        mm = ModuleManager(module=module)
458        mm.is_version_less_than_13 = Mock(return_value=True)
459        mm.get_manager = Mock(return_value=upm)
460
461        results = mm.exec_module()
462
463        assert results['changed'] is True
464        assert results['shell'] == 'bash'
465
466    def test_update_user_shell_to_bash_mutliple_roles(self, *args):
467        set_module_args(dict(
468            username_credential='someuser',
469            shell='bash',
470            provider=dict(
471                server='localhost',
472                password='password',
473                user='admin'
474            )
475        ))
476
477        module = AnsibleModule(
478            argument_spec=self.spec.argument_spec,
479            supports_check_mode=self.spec.supports_check_mode
480        )
481
482        # Configure the parameters that would be returned by querying the
483        # remote device
484        access = [
485            {'name': 'Common', 'role': 'operator'},
486            {'name': 'all', 'role': 'guest'}
487        ]
488        current = Parameters(
489            params=dict(
490                user='admin',
491                shell='tmsh',
492                partition_access=access
493            )
494        )
495
496        # Override methods to force specific logic in the module to happen
497        upm = UnpartitionedManager(module=module, params=module.params)
498        upm.exists = Mock(return_value=True)
499        upm.update_on_device = Mock(return_value=True)
500        upm.read_current_from_device = Mock(return_value=current)
501
502        mm = ModuleManager(module=module)
503        mm.is_version_less_than_13 = Mock(return_value=True)
504        mm.get_manager = Mock(return_value=upm)
505
506        msg = "Shell access is only available to 'admin' or " \
507              "'resource-admin' roles."
508
509        with pytest.raises(F5ModuleError) as ex:
510            mm.exec_module()
511        assert str(ex.value) == msg
512
513
514class TestLegacyManager(unittest.TestCase):
515
516    def setUp(self):
517        self.spec = ArgumentSpec()
518
519    def test_create_user(self, *args):
520        access = [{'name': 'Common', 'role': 'guest'}]
521        set_module_args(dict(
522            username_credential='someuser',
523            password_credential='testpass',
524            partition_access=access,
525            update_password='on_create',
526            provider=dict(
527                server='localhost',
528                password='password',
529                user='admin'
530            )
531        ))
532
533        module = AnsibleModule(
534            argument_spec=self.spec.argument_spec,
535            supports_check_mode=self.spec.supports_check_mode
536        )
537
538        # Override methods to force specific logic in the module to happen
539        upm = UnpartitionedManager(module=module, params=module.params)
540        upm.create_on_device = Mock(return_value=True)
541        upm.exists = Mock(return_value=False)
542
543        mm = ModuleManager(module=module)
544        mm.is_version_less_than_13 = Mock(return_value=True)
545        mm.get_manager = Mock(return_value=upm)
546
547        results = mm.exec_module()
548
549        assert results['changed'] is True
550        assert results['partition_access'] == access
551
552    def test_create_user_no_password(self, *args):
553        access = [{'name': 'Common', 'role': 'guest'}]
554        set_module_args(dict(
555            username_credential='someuser',
556            partition_access=access,
557            provider=dict(
558                server='localhost',
559                password='password',
560                user='admin'
561            )
562        ))
563
564        module = AnsibleModule(
565            argument_spec=self.spec.argument_spec,
566            supports_check_mode=self.spec.supports_check_mode
567        )
568
569        # Override methods to force specific logic in the module to happen
570        upm = UnpartitionedManager(module=module, params=module.params)
571        upm.create_on_device = Mock(return_value=True)
572        upm.exists = Mock(return_value=False)
573
574        mm = ModuleManager(module=module)
575        mm.is_version_less_than_13 = Mock(return_value=True)
576        mm.get_manager = Mock(return_value=upm)
577
578        results = mm.exec_module()
579
580        assert results['changed'] is True
581        assert results['partition_access'] == access
582
583    def test_create_user_partition_access_raises(self, *args):
584        set_module_args(dict(
585            username_credential='someuser',
586            provider=dict(
587                server='localhost',
588                password='password',
589                user='admin'
590            )
591        ))
592
593        module = AnsibleModule(
594            argument_spec=self.spec.argument_spec,
595            supports_check_mode=self.spec.supports_check_mode
596        )
597
598        # Override methods to force specific logic in the module to happen
599        upm = UnpartitionedManager(module=module, params=module.params)
600        upm.create_on_device = Mock(return_value=True)
601        upm.exists = Mock(return_value=False)
602
603        mm = ModuleManager(module=module)
604        mm.is_version_less_than_13 = Mock(return_value=True)
605        mm.get_manager = Mock(return_value=upm)
606
607        msg = "The 'partition_access' option " \
608              "is required when creating a resource."
609
610        with pytest.raises(F5ModuleError) as ex:
611            mm.exec_module()
612        assert str(ex.value) == msg
613
614    def test_create_user_shell_bash(self, *args):
615        access = [{'name': 'all', 'role': 'admin'}]
616        set_module_args(dict(
617            username_credential='someuser',
618            password_credential='testpass',
619            partition_access=access,
620            update_password='on_create',
621            shell='bash',
622            provider=dict(
623                server='localhost',
624                password='password',
625                user='admin'
626            )
627        ))
628
629        module = AnsibleModule(
630            argument_spec=self.spec.argument_spec,
631            supports_check_mode=self.spec.supports_check_mode
632        )
633
634        # Override methods to force specific logic in the module to happen
635        upm = UnpartitionedManager(module=module, params=module.params)
636        upm.create_on_device = Mock(return_value=True)
637        upm.exists = Mock(return_value=False)
638
639        mm = ModuleManager(module=module)
640        mm.is_version_less_than_13 = Mock(return_value=True)
641        mm.get_manager = Mock(return_value=upm)
642
643        results = mm.exec_module()
644
645        assert results['changed'] is True
646        assert results['partition_access'] == access
647
648    def test_create_user_shell_not_permitted_raises(self, *args):
649        access = [{'name': 'Common', 'role': 'guest'}]
650        set_module_args(dict(
651            username_credential='someuser',
652            password_credential='testpass',
653            partition_access=access,
654            update_password='on_create',
655            shell='bash',
656            provider=dict(
657                server='localhost',
658                password='password',
659                user='admin'
660            )
661        ))
662
663        module = AnsibleModule(
664            argument_spec=self.spec.argument_spec,
665            supports_check_mode=self.spec.supports_check_mode
666        )
667
668        # Override methods to force specific logic in the module to happen
669        upm = UnpartitionedManager(module=module, params=module.params)
670        upm.create_on_device = Mock(return_value=True)
671        upm.exists = Mock(return_value=False)
672
673        mm = ModuleManager(module=module)
674        mm.is_version_less_than_13 = Mock(return_value=True)
675        mm.get_manager = Mock(return_value=upm)
676
677        msg = "Shell access is only available to 'admin' or " \
678              "'resource-admin' roles."
679
680        with pytest.raises(F5ModuleError) as ex:
681            mm.exec_module()
682        assert str(ex.value) == msg
683
684    def test_update_user_password(self, *args):
685        set_module_args(dict(
686            username_credential='someuser',
687            password_credential='testpass',
688            provider=dict(
689                server='localhost',
690                password='password',
691                user='admin'
692            )
693        ))
694
695        module = AnsibleModule(
696            argument_spec=self.spec.argument_spec,
697            supports_check_mode=self.spec.supports_check_mode
698        )
699
700        # Configure the parameters that would be returned by querying the
701        # remote device
702        access = [{'name': 'Common', 'role': 'guest'}]
703        current = Parameters(
704            params=dict(
705                shell='tmsh',
706                partition_access=access
707            )
708        )
709
710        # Override methods to force specific logic in the module to happen
711        upm = UnpartitionedManager(module=module, params=module.params)
712        upm.exists = Mock(return_value=True)
713        upm.update_on_device = Mock(return_value=True)
714        upm.read_current_from_device = Mock(return_value=current)
715
716        mm = ModuleManager(module=module)
717        mm.is_version_less_than_13 = Mock(return_value=True)
718        mm.get_manager = Mock(return_value=upm)
719
720        results = mm.exec_module()
721
722        assert results['changed'] is True
723
724    def test_update_user_shell_to_none(self, *args):
725        set_module_args(dict(
726            username_credential='someuser',
727            shell='none',
728            provider=dict(
729                server='localhost',
730                password='password',
731                user='admin'
732            )
733        ))
734
735        module = AnsibleModule(
736            argument_spec=self.spec.argument_spec,
737            supports_check_mode=self.spec.supports_check_mode
738        )
739
740        # Configure the parameters that would be returned by querying the
741        # remote device
742        current = Parameters(
743            params=dict(
744                user='admin',
745                shell='tmsh'
746            )
747        )
748
749        # Override methods to force specific logic in the module to happen
750        upm = UnpartitionedManager(module=module, params=module.params)
751        upm.exists = Mock(return_value=True)
752        upm.update_on_device = Mock(return_value=True)
753        upm.read_current_from_device = Mock(return_value=current)
754
755        mm = ModuleManager(module=module)
756        mm.is_version_less_than_13 = Mock(return_value=True)
757        mm.get_manager = Mock(return_value=upm)
758
759        results = mm.exec_module()
760
761        assert results['changed'] is True
762        assert results['shell'] == 'none'
763
764    def test_update_user_shell_to_none_shell_attribute_missing(self, *args):
765        set_module_args(dict(
766            username_credential='someuser',
767            shell='none',
768            provider=dict(
769                server='localhost',
770                password='password',
771                user='admin'
772            )
773        ))
774
775        module = AnsibleModule(
776            argument_spec=self.spec.argument_spec,
777            supports_check_mode=self.spec.supports_check_mode
778        )
779
780        # Configure the parameters that would be returned by querying the
781        # remote device
782        access = [{'name': 'Common', 'role': 'guest'}]
783        current = Parameters(
784            params=dict(
785                user='admin',
786                partition_access=access
787            )
788        )
789
790        # Override methods to force specific logic in the module to happen
791        upm = UnpartitionedManager(module=module, params=module.params)
792        upm.exists = Mock(return_value=True)
793        upm.update_on_device = Mock(return_value=True)
794        upm.read_current_from_device = Mock(return_value=current)
795
796        mm = ModuleManager(module=module)
797        mm.is_version_less_than_13 = Mock(return_value=True)
798        mm.get_manager = Mock(return_value=upm)
799
800        results = mm.exec_module()
801
802        assert results['changed'] is False
803        assert not hasattr(results, 'shell')
804
805    def test_update_user_shell_to_bash(self, *args):
806        set_module_args(dict(
807            username_credential='someuser',
808            shell='bash',
809            provider=dict(
810                server='localhost',
811                password='password',
812                user='admin'
813            )
814        ))
815
816        module = AnsibleModule(
817            argument_spec=self.spec.argument_spec,
818            supports_check_mode=self.spec.supports_check_mode
819        )
820
821        # Configure the parameters that would be returned by querying the
822        # remote device
823        access = [{'name': 'all', 'role': 'admin'}]
824        current = Parameters(
825            params=dict(
826                user='admin',
827                shell='tmsh',
828                partition_access=access
829            )
830        )
831
832        # Override methods to force specific logic in the module to happen
833        upm = UnpartitionedManager(module=module, params=module.params)
834        upm.exists = Mock(return_value=True)
835        upm.update_on_device = Mock(return_value=True)
836        upm.read_current_from_device = Mock(return_value=current)
837
838        mm = ModuleManager(module=module)
839        mm.is_version_less_than_13 = Mock(return_value=True)
840        mm.get_manager = Mock(return_value=upm)
841
842        results = mm.exec_module()
843
844        assert results['changed'] is True
845        assert results['shell'] == 'bash'
846
847    def test_update_user_shell_to_bash_mutliple_roles(self, *args):
848        set_module_args(dict(
849            username_credential='someuser',
850            shell='bash',
851            provider=dict(
852                server='localhost',
853                password='password',
854                user='admin'
855            )
856        ))
857
858        module = AnsibleModule(
859            argument_spec=self.spec.argument_spec,
860            supports_check_mode=self.spec.supports_check_mode
861        )
862
863        # Configure the parameters that would be returned by querying the
864        # remote device
865        access = [
866            {'name': 'Common', 'role': 'operator'},
867            {'name': 'all', 'role': 'guest'}
868        ]
869        current = Parameters(
870            params=dict(
871                user='admin',
872                shell='tmsh',
873                partition_access=access
874            )
875        )
876
877        # Override methods to force specific logic in the module to happen
878        upm = UnpartitionedManager(module=module, params=module.params)
879        upm.exists = Mock(return_value=True)
880        upm.update_on_device = Mock(return_value=True)
881        upm.read_current_from_device = Mock(return_value=current)
882
883        mm = ModuleManager(module=module)
884        mm.is_version_less_than_13 = Mock(return_value=True)
885        mm.get_manager = Mock(return_value=upm)
886
887        msg = "Shell access is only available to 'admin' or " \
888              "'resource-admin' roles."
889
890        with pytest.raises(F5ModuleError) as ex:
891            mm.exec_module()
892        assert str(ex.value) == msg
893