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