Skip to content

Commit 8ab92e2

Browse files
committed
Added more functional tests, reworked the helper methods as per discussion with @pjbreaux
1 parent fa76ba6 commit 8ab92e2

5 files changed

Lines changed: 117 additions & 40 deletions

File tree

f5/bigip/mixins.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,6 @@ class UnsupportedTmosVersion(F5SDKError):
3939
pass
4040

4141

42-
class MissingRequiredCommandParameter(F5SDKError):
43-
"""Various values MUST be provided to execute a command."""
44-
pass
45-
46-
4742
class LazyAttributesRequired(F5SDKError):
4843
"""Raised when a object accesses a lazy attribute that is not listed"""
4944
pass
@@ -257,11 +252,7 @@ def _exec_cmd(self, command, **kwargs):
257252
kwargs['command'] = command
258253
self._check_exclusive_parameters(**kwargs)
259254
requests_params = self._handle_requests_params(kwargs)
260-
rset = self._meta_data['required_command_parameters']
261-
check = self._check_required_parameters(rset, **kwargs)
262-
if check:
263-
error_message = 'Missing required params: {}'.format(check[1])
264-
raise MissingRequiredCommandParameter(error_message)
255+
self._check_command_parameters(**kwargs)
265256
session = self._meta_data['bigip']._meta_data['icr_session']
266257
response = session.post(
267258
self._meta_data['uri'], json=kwargs, **requests_params)

f5/bigip/resource.py

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,18 @@
8787
from requests.exceptions import HTTPError
8888

8989

90-
class ExclusiveAttributesPresent(F5SDKError):
91-
"""Raises this when exclusive attributes are present
90+
class MissingRequiredCommandParameter(F5SDKError):
91+
"""Various values MUST be provided to execute a command."""
92+
pass
9293

93-
during resource creation
94-
"""
94+
95+
class ExclusiveAttributesPresent(F5SDKError):
96+
"""Raises this when exclusive attributes are present."""
9597
pass
9698

9799

98100
class MissingUpdateParameter(F5SDKError):
99-
"""Raises this when update requires specific
100-
101-
parameters together
102-
"""
101+
"""Raises this when update requires specific parameters together."""
103102
pass
104103

105104

@@ -209,9 +208,34 @@ def _check_load_parameters(self, **kwargs):
209208
:raises: MissingRequiredReadParameter
210209
"""
211210
rset = self._meta_data['required_load_parameters']
212-
check = self._check_required_parameters(rset, **kwargs)
211+
check = self._missing_required_parameters(rset, **kwargs)
212+
if check:
213+
error_message = 'Missing required params: %s' % check
214+
raise MissingRequiredReadParameter(error_message)
215+
216+
def _check_create_parameters(self, **kwargs):
217+
"""Params given to create should satisfy required params.
218+
219+
:params: kwargs
220+
:raises: MissingRequiredCreateParameter
221+
"""
222+
rset = self._meta_data['required_creation_parameters']
223+
check = self._missing_required_parameters(rset, **kwargs)
213224
if check:
214-
raise MissingRequiredReadParameter(check[1])
225+
error_message = 'Missing required params: %s' % check
226+
raise MissingRequiredCreationParameter(error_message)
227+
228+
def _check_command_parameters(self, **kwargs):
229+
"""Params given to exec_cmd should satisfy required params.
230+
231+
:params: kwargs
232+
:raises: MissingRequiredCommandParameter
233+
"""
234+
rset = self._meta_data['required_command_parameters']
235+
check = self._missing_required_parameters(rset, **kwargs)
236+
if check:
237+
error_message = 'Missing required params: %s' % check
238+
raise MissingRequiredCommandParameter(error_message)
215239

216240
def _local_update(self, rdict):
217241
"""Call this with a response dictionary to update instance attrs.
@@ -322,19 +346,19 @@ def _check_exclusive_parameters(self, **kwargs):
322346
raise ExclusiveAttributesPresent(error)
323347

324348
@staticmethod
325-
def _check_required_parameters(rqset, **kwargs):
326-
"""Helper function to do operation on sets
349+
def _missing_required_parameters(rqset, **kwargs):
350+
"""Helper function to do operation on sets.
351+
352+
Checks for any missing required parameters.
353+
Returns non-empty or empty list. With empty
354+
list being False.
327355
328-
::returns bool and variable
356+
::returns list
329357
"""
330358
key_set = set(kwargs.keys())
331359
required_minus_received = rqset - key_set
332360
if required_minus_received != set():
333-
error_message = 'Missing required params: %s' % \
334-
required_minus_received
335-
return True, error_message
336-
else:
337-
return False
361+
return list(required_minus_received)
338362

339363
@property
340364
def raw(self):
@@ -704,13 +728,7 @@ def _create(self, **kwargs):
704728
raise URICreationCollision(error)
705729
self._check_exclusive_parameters(**kwargs)
706730
requests_params = self._handle_requests_params(kwargs)
707-
708-
# Using helper method to check for required keys.
709-
# Defining convenience variables to make code readable
710-
rset = self._meta_data['required_creation_parameters']
711-
check = self._check_required_parameters(rset, **kwargs)
712-
if check:
713-
raise MissingRequiredCreationParameter(check[1])
731+
self._check_create_parameters(**kwargs)
714732

715733
# Make convenience variable with short names for this method.
716734
_create_uri = self._meta_data['container']._meta_data['uri']

f5/bigip/test/test_resource.py

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@
1818

1919
from f5.bigip.resource import Collection
2020
from f5.bigip.resource import DeviceProvidesIncompatibleKey
21+
from f5.bigip.resource import ExclusiveAttributesPresent
2122
from f5.bigip.resource import GenerationMismatch
2223
from f5.bigip.resource import InvalidForceType
2324
from f5.bigip.resource import InvalidResource
2425
from f5.bigip.resource import KindTypeMismatch
26+
from f5.bigip.resource import MissingRequiredCommandParameter
2527
from f5.bigip.resource import MissingRequiredCreationParameter
2628
from f5.bigip.resource import MissingRequiredReadParameter
2729
from f5.bigip.resource import OrganizingCollection
30+
from f5.bigip.resource import PathElement
2831
from f5.bigip.resource import RequestParamKwargCollision
2932
from f5.bigip.resource import Resource
3033
from f5.bigip.resource import ResourceBase
@@ -96,7 +99,7 @@ def test_missing_required_creation_parameter(self):
9699
with pytest.raises(MissingRequiredCreationParameter) as MRCPEIO:
97100
r.create(partition="Common", name='CreateTest')
98101
assert MRCPEIO.value.message ==\
99-
"Missing required params: set(['NONEMPTY'])"
102+
"Missing required params: ['NONEMPTY']"
100103

101104
def test_KindTypeMismatch(self):
102105
r = Resource(mock.MagicMock())
@@ -290,7 +293,7 @@ def test_missing_required_params(self):
290293
with pytest.raises(MissingRequiredReadParameter) as MRREIO:
291294
r.load(partition='Common', name='test_load')
292295
assert MRREIO.value.message ==\
293-
"Missing required params: set(['IMPOSSIBLE'])"
296+
"Missing required params: ['IMPOSSIBLE']"
294297

295298
def test_requests_params_collision(self):
296299
r = Resource(mock.MagicMock())
@@ -443,3 +446,64 @@ def test_collection_s():
443446
}
444447
tc_s = Under_s(MC)
445448
assert tc_s._meta_data['uri'] == 'BASEURI/under/'
449+
450+
451+
class TestPathElement(object):
452+
453+
def test_missing_req_param_true(self):
454+
p = PathElement(mock.MagicMock())
455+
rqset = set(['FOOPAR1', 'FOOPAR2'])
456+
fakearg = {'FOOPAR1': 'FOOVAL'}
457+
mrq = p._missing_required_parameters(rqset, **fakearg)
458+
assert mrq
459+
assert mrq == ['FOOPAR2']
460+
461+
def test_missing_req_param_false(self):
462+
p = PathElement(mock.MagicMock())
463+
rqset = set(['FOOPAR1'])
464+
fakearg = {'FOOPAR1': 'FOOVAL'}
465+
mrq = p._missing_required_parameters(rqset, **fakearg)
466+
assert not mrq
467+
468+
def test_check_load_parameters_fail(self):
469+
p = PathElement(mock.MagicMock())
470+
p._meta_data['required_load_parameters'] = set(['FAKELOAD'])
471+
with pytest.raises(MissingRequiredReadParameter) as RLPEIO:
472+
p._check_load_parameters(FOOLOAD='FOOVAL')
473+
assert "['FAKELOAD']" in RLPEIO.value.message
474+
475+
def test_check_create_parameters_fail(self):
476+
p = PathElement(mock.MagicMock())
477+
p._meta_data['required_creation_parameters'] = set(['FAKECREATE'])
478+
with pytest.raises(MissingRequiredCreationParameter) as RCPEIO:
479+
p._check_create_parameters(FOOCREATE='FOOVAL')
480+
assert "['FAKECREATE']" in RCPEIO.value.message
481+
482+
def test_check_command_parameters_fail(self):
483+
p = PathElement(mock.MagicMock())
484+
p._meta_data['required_command_parameters'] = set(['FAKECOMMAND'])
485+
with pytest.raises(MissingRequiredCommandParameter) as RCPEIO:
486+
p._check_command_parameters(BARCOMMAND='FOOVAL')
487+
assert "['FAKECOMMAND']" in RCPEIO.value.message
488+
489+
def test_check_exclusive_parameters_empty_attr(self):
490+
p = PathElement(mock.MagicMock())
491+
p._meta_data['exclusive_attributes'] = []
492+
fakearg = {'FOOEX': 'FOOVAL'}
493+
# Check that any other exception is not thrown
494+
p._check_exclusive_parameters(**fakearg)
495+
496+
def test_check_exclusive_parameters_pass(self):
497+
p = PathElement(mock.MagicMock())
498+
p._meta_data['exclusive_attributes'] = [('FOOEX', 'BAREX')]
499+
fakearg = {'FOOEX': 'FOOVAL'}
500+
# Check ExclusiveAttributesPresent is not thrown
501+
p._check_exclusive_parameters(**fakearg)
502+
503+
def test_check_exclusive_parameters_fail(self):
504+
p = PathElement(mock.MagicMock())
505+
p._meta_data['exclusive_attributes'] = [('FOOEX', 'BAREX')]
506+
fakearg = {'FOOEX': 'FOOVAL', 'BAREX': 'BARVAL'}
507+
with pytest.raises(ExclusiveAttributesPresent) as EAEIO:
508+
p._check_exclusive_parameters(**fakearg)
509+
assert 'FOOEX, BAREX' in EAEIO.value.message

f5/bigip/tm/sys/test/test_sys_application.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,13 +279,13 @@ def test_load_no_args(self, FakeService):
279279
with pytest.raises(MissingRequiredReadParameter) as ex:
280280
FakeService.load()
281281
assert ex.value.message == \
282-
"Missing required params: set(['partition', 'name'])"
282+
"Missing required params: ['partition', 'name']"
283283

284284
def test_load_no_partition(self, FakeService):
285285
with pytest.raises(MissingRequiredReadParameter) as ex:
286286
FakeService.load(name='test_service')
287287
assert ex.value.message == \
288-
"Missing required params: set(['partition'])"
288+
"Missing required params: ['partition']"
289289

290290

291291
class TestServiceUpdate(object):

test/functional/tm/sys/test_failover.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from f5.bigip.tm.sys.failover import InvalidParameterValue
1717
from pprint import pprint as pp
1818

19+
import time
1920
import pytest
2021

2122

@@ -68,9 +69,12 @@ def test_exec_cmd(self, bigip):
6869

6970
def test_exec_cmd_cmdargs(self, bigip):
7071
f = bigip.sys.failover
71-
f.exec_cmd('run', utilCmdArgs='offline persist')
72+
f.exec_cmd('run', utilCmdArgs='offline')
7273
fl = bigip.sys.failover.load()
7374
assert 'Failover forced_offline' in fl.apiRawValues['apiAnonymous']
7475
f.exec_cmd('run', utilCmdArgs='online')
76+
# We need this 1 sec delay as sometimes the status does not change
77+
# straight away, causing the assertion to fail.
78+
time.sleep(1)
7579
fl.refresh()
7680
assert 'Failover active' in fl.apiRawValues['apiAnonymous']

0 commit comments

Comments
 (0)