1616import pytest
1717import requests
1818
19+ from f5 .bigip .resource import AttemptedMutationOfReadOnly
1920from f5 .bigip .resource import BooleansToReduceHaveSameValue
2021from f5 .bigip .resource import Collection
2122from f5 .bigip .resource import DeviceProvidesIncompatibleKey
3536from f5 .bigip .resource import UnnamedResource
3637from f5 .bigip .resource import UnregisteredKind
3738from f5 .bigip .resource import URICreationCollision
39+ from f5 .bigip .tm .cm .sync_status import Sync_Status
3840from f5 .bigip .tm .ltm .virtual import Virtual
3941from f5 .sdk_exception import UnsupportedMethod
4042
@@ -57,7 +59,8 @@ def fake_rsrc():
5759 r ._meta_data ['uri' ] = 'URI'
5860 r ._meta_data ['read_only_attributes' ] = [u"READONLY" ]
5961 attrs = {'put.return_value' : MockResponse ({u"generation" : 0 }),
60- 'get.return_value' : MockResponse ({u"generation" : 0 })}
62+ 'get.return_value' : MockResponse ({u"generation" : 0 }),
63+ 'patch.return_value' : MockResponse ({u"generation" : 0 })}
6164 mock_session = mock .MagicMock (** attrs )
6265 r ._meta_data ['bigip' ]._meta_data = {'icr_session' : mock_session }
6366 return r
@@ -217,16 +220,18 @@ def test__create_with_Collision():
217220
218221
219222class TestResource_update (object ):
220- def itest__check_generation_with_mismatch (self ):
223+ def test__check_generation_with_mismatch (self ):
221224 # generation is borked server-side
222225 r = Resource (mock .MagicMock ())
223226 r ._meta_data ['allowed_lazy_attributes' ] = []
224227 r ._meta_data ['uri' ] = 'URI'
225228 r ._meta_data ['bigip' ]._meta_data ['icr_session' ].get .return_value = \
226229 MockResponse ({u"generation" : 0 })
230+ r ._meta_data ['bigip' ]._meta_data ['icr_session' ].put .return_value = \
231+ MockResponse ({u"generation" : 0 })
227232 r .generation = 1
228233 with pytest .raises (GenerationMismatch ) as GMEIO :
229- r .update (a = u"b" )
234+ r .update (a = u"b" , force = False )
230235 assert GMEIO .value .message == \
231236 'The generation of the object on the BigIP (0)' \
232237 ' does not match the current object(1)'
@@ -243,6 +248,7 @@ def test__meta_data_state(self):
243248 pre_meta = r ._meta_data .copy ()
244249 r .update (a = u"b" )
245250 assert pre_meta == r ._meta_data
251+ assert r .raw == r .__dict__
246252
247253 def test_Collection_removal (self ):
248254 r = Resource (mock .MagicMock ())
@@ -280,22 +286,22 @@ def test_read_only_removal(self):
280286
281287 def test_reduce_boolean_removes_enabled (self , fake_rsrc ):
282288 fake_rsrc .update (enabled = False )
283- pos , kwargs = fake_rsrc ._meta_data ['bigip' ]._meta_data [ 'icr_session' ]. put . \
284- call_args
289+ pos , kwargs = fake_rsrc ._meta_data ['bigip' ].\
290+ _meta_data [ 'icr_session' ]. put . call_args
285291 assert kwargs ['json' ]['disabled' ] is True
286292 assert 'enabled' not in kwargs ['json' ]
287293
288294 def test_reduce_boolean_removes_disabled (self , fake_rsrc ):
289295 fake_rsrc .update (disabled = False )
290- pos , kwargs = fake_rsrc ._meta_data ['bigip' ]._meta_data [ 'icr_session' ]. put . \
291- call_args
296+ pos , kwargs = fake_rsrc ._meta_data ['bigip' ].\
297+ _meta_data [ 'icr_session' ]. put . call_args
292298 assert kwargs ['json' ]['enabled' ] is True
293299 assert 'disabled' not in kwargs ['json' ]
294300
295301 def test_reduce_boolean_removes_nothing (self , fake_rsrc ):
296302 fake_rsrc .update (partition = 'Common' , name = 'test_create' , enabled = True )
297- pos , kwargs = fake_rsrc ._meta_data ['bigip' ]._meta_data [ 'icr_session' ]. put . \
298- call_args
303+ pos , kwargs = fake_rsrc ._meta_data ['bigip' ].\
304+ _meta_data [ 'icr_session' ]. put . call_args
299305 assert kwargs ['json' ]['enabled' ] is True
300306 assert 'disabled' not in kwargs ['json' ]
301307
@@ -313,6 +319,87 @@ def test_reduce_boolean_same_value(self, fake_rsrc):
313319 assert msg == ex .value .message
314320
315321
322+ class TestResource_modify (object ):
323+
324+ def test__meta_data_state (self ):
325+ r = Resource (mock .MagicMock ())
326+ r ._meta_data ['allowed_lazy_attributes' ] = []
327+ r ._meta_data ['uri' ] = 'URI'
328+ r ._meta_data ['bigip' ]._meta_data ['icr_session' ].get .return_value = \
329+ MockResponse ({u"generation" : 0 })
330+ r ._meta_data ['bigip' ]._meta_data ['icr_session' ].patch .return_value = \
331+ MockResponse ({u"generation" : 0 })
332+ r .generation = 0
333+ pre_meta = r ._meta_data .copy ()
334+ r .modify (a = u"b" )
335+ assert pre_meta == r ._meta_data
336+
337+ def test_Collection_removal (self ):
338+ r = Resource (mock .MagicMock ())
339+ r ._meta_data ['allowed_lazy_attributes' ] = []
340+ r ._meta_data ['uri' ] = 'URI'
341+ attrs = {'patch.return_value' : MockResponse ({u"generation" : 0 }),
342+ 'get.return_value' : MockResponse ({u"generation" : 0 })}
343+ mock_session = mock .MagicMock (** attrs )
344+ r ._meta_data ['bigip' ]._meta_data = {'icr_session' : mock_session }
345+ r .generation = 0
346+ r .contained = Collection (mock .MagicMock ())
347+ assert 'contained' in r .__dict__
348+ r .modify (a = u"b" )
349+ submitted = r ._meta_data ['bigip' ]. \
350+ _meta_data ['icr_session' ].patch .call_args [1 ]['json' ]
351+
352+ assert 'contained' not in submitted
353+
354+ def test_read_only_validate (self ):
355+ r = Resource (mock .MagicMock ())
356+ r ._meta_data ['allowed_lazy_attributes' ] = []
357+ r ._meta_data ['uri' ] = 'URI'
358+ r ._meta_data ['read_only_attributes' ] = [u"READONLY" ]
359+ attrs = {'patch.return_value' : MockResponse ({u"generation" : 0 }),
360+ 'get.return_value' : MockResponse ({u"generation" : 0 })}
361+ mock_session = mock .MagicMock (** attrs )
362+ r ._meta_data ['bigip' ]._meta_data = {'icr_session' : mock_session }
363+ r .generation = 0
364+ with pytest .raises (AttemptedMutationOfReadOnly ) as AMOROEIO :
365+ r .modify (READONLY = True )
366+ assert "READONLY" in AMOROEIO .value .message
367+
368+ def test_reduce_boolean_removes_enabled (self , fake_rsrc ):
369+ fake_rsrc .modify (enabled = False )
370+ pos , kwargs = fake_rsrc ._meta_data ['bigip' ].\
371+ _meta_data ['icr_session' ].patch .call_args
372+ assert kwargs ['json' ]['disabled' ] is True
373+ assert 'enabled' not in kwargs ['json' ]
374+
375+ def test_reduce_boolean_removes_disabled (self , fake_rsrc ):
376+ fake_rsrc .modify (disabled = False )
377+ pos , kwargs = fake_rsrc ._meta_data ['bigip' ].\
378+ _meta_data ['icr_session' ].patch .call_args
379+ assert kwargs ['json' ]['enabled' ] is True
380+ assert 'disabled' not in kwargs ['json' ]
381+
382+ def test_reduce_boolean_removes_nothing (self , fake_rsrc ):
383+ fake_rsrc .modify (partition = 'Common' , name = 'test_create' , enabled = True )
384+ pos , kwargs = fake_rsrc ._meta_data ['bigip' ].\
385+ _meta_data ['icr_session' ].patch .call_args
386+ assert kwargs ['json' ]['enabled' ] is True
387+ assert 'disabled' not in kwargs ['json' ]
388+
389+ def test_reduce_boolean_same_value (self , fake_rsrc ):
390+ with pytest .raises (BooleansToReduceHaveSameValue ) as ex :
391+ fake_rsrc .modify (
392+ partition = 'Common' ,
393+ name = 'test_create' ,
394+ enabled = True ,
395+ disabled = True
396+ )
397+ msg = 'Boolean pair, enabled and disabled, have same value: True. ' \
398+ 'If both are given to this method, they cannot be the same, as ' \
399+ 'this method cannot decide which one should be True.'
400+ assert msg == ex .value .message
401+
402+
316403class TestResource_delete (object ):
317404 def test_success (self ):
318405 r = Resource (mock .MagicMock ())
@@ -455,6 +542,34 @@ def test_success(self):
455542 x = r .load (partition = 'Common' , name = 'test_load' )
456543 assert x .selfLink == mockuri
457544
545+ def test_URICreationCollision (self ):
546+ r = Virtual (mock .MagicMock ())
547+ r ._meta_data ['allowed_lazy_attributes' ] = []
548+ mockuri = "https://localhost:443/mgmt/tm/ltm/virtual/~Common~test_load"
549+ attrs = {'get.return_value' :
550+ MockResponse (
551+ {
552+ u"generation" : 0 ,
553+ u"selfLink" : mockuri ,
554+ u"kind" : u"tm:ltm:virtual:virtualstate"
555+ }
556+ )}
557+ mock_session = mock .MagicMock (** attrs )
558+ r ._meta_data ['bigip' ]._meta_data = \
559+ {'icr_session' : mock_session ,
560+ 'hostname' : 'TESTDOMAINNAME' ,
561+ 'uri' : 'https://TESTDOMAIN:443/mgmt/tm/' }
562+ r .generation = 0
563+ x = r .load (partition = 'Common' , name = 'test_load' )
564+ assert x .selfLink == mockuri
565+ with pytest .raises (URICreationCollision ) as UCCEIO :
566+ x .load (uri = 'URI' )
567+ assert UCCEIO .value .message == \
568+ "There was an attempt to assign a new uri to this resource, the" \
569+ " _meta_data['uri'] is " \
570+ "https://TESTDOMAIN:443/mgmt/tm/ltm/virtual/" \
571+ "~Common~test_load/ and it should not be changed."
572+
458573
459574class TestResource_exists (object ):
460575 def test_loadable (self ):
@@ -621,4 +736,25 @@ def test_create_raises(self):
621736 def test_delete_raises (self ):
622737 unnamed_resource = UnnamedResource (mock .MagicMock ())
623738 with pytest .raises (UnsupportedMethod ):
624- unnamed_resource .create ()
739+ unnamed_resource .delete ()
740+
741+ def test_load (self ):
742+ r = Sync_Status (mock .MagicMock ())
743+ r ._meta_data ['allowed_lazy_attributes' ] = []
744+ mockuri = "https://localhost:443/mgmt/tm/cm/sync-status"
745+ attrs = {'get.return_value' :
746+ MockResponse (
747+ {
748+ u"generation" : 0 ,
749+ u"selfLink" : mockuri ,
750+ u"kind" : u"tm:cm:sync-status:sync-statusstats"
751+ }
752+ )}
753+ mock_session = mock .MagicMock (** attrs )
754+ r ._meta_data ['bigip' ]._meta_data = \
755+ {'icr_session' : mock_session ,
756+ 'hostname' : 'TESTDOMAINNAME' ,
757+ 'uri' : 'https://TESTDOMAIN:443/mgmt/tm/' }
758+ r .generation = 0
759+ x = r .load (partition = 'Common' , name = 'test_load' )
760+ assert x .selfLink == 'https://localhost:443/mgmt/tm/cm/sync-status'
0 commit comments