Re: [389-devel] Proof of concept: mocking DS in lib389

2013-10-29 Thread Jan Rusnacko
Hello Thierry,

I am not rewriting ldapadd,...  methods of real DS class, I am in fact
creating MockDS class with custom ldapadd,... methods, _just_ like you suggest 
:)

Furthermore, you can view it as a subclass of real_ds - even though it is not
a proper Python subclass, it inherits all functions from repl module just like
real_ds would (again through ModuleProxy mechanism). So, methods that are
defined in repl are the same for real_ds class and for MockDS class, but
ldap.. methods are different. So, basically exactly what you suggest :)

Code of the whole class along with all methods is in file
tests/test_dsmodules/conftest.py line 7.

Thank you,
Jan

On 10/28/2013 12:02 PM, thierry bordaz wrote:
 Hi Jan,
 
 That is very impressive POC, far above my skill in python. Thanks for
 sharing this.
 I have a novice question.
 This implementation overwrites the basic ldapadd,ldapsearch... function of
 the real DS.
 An other approach is to write a 'mock_ds' class being a subclass of
 'real_ds' and to overwrite the ldapadd,ldapsearch in mock_ds class (to 
 store
 data into a dict). What would be the advantages of your approach ?
 
 best regards
 thierry
 
 On 10/25/2013 09:36 PM, Jan Rusnacko wrote:
 Hello Roberto and Thierry,

 as I promised, I am sending you a proof-of-concept code that demonstrates, 
 how
 we can mock DS in unit tests for library function (see attachment). You can 
 run
 tests just by executing py.test in tests directory.

 Only 3 files are of interest here:

 lib389/dsmodules/repl.py - this is a Python module with functions - they 
 expect
 DS instance as the first argument. Since they are functions, not methods, I 
 can
 just mock DS and pass that fake one as the first argument to them in unit 
 tests.

 tests/test_dsmodules/conftest.py - this file contains definition of mock DS
 class along with py.test fixture, that returns it.

 tests/test_dsmodules/test_repl.py - this contains unit tests for functions 
 from
 repl.py.

 What I do is quite simple - I override ldapadd, ldapdelete .. methods of 
 mock DS
 class, so that instead of sending command to real DS instance, they just 
 store
 the data in 'dit' dictionary (which represents content stored in DS). This 
 way,
 I can check that when I call e.g. function enable_changelog(..), in the end 
 DS
 will have correct changelog entry.

 To put it very bluntly - enable_changelog(..) function just adds correct
 changelog entry to whatever is passed to it as the first argument. In unit
 tests, it is mock DS, otherwise it would be real DS class that sends real 
 ldap
 commands to real DS instance behind.

 Now I can successfully test that enable_changelog really works, without going
 into trouble defining DSInstance or ldap calls at all. Also, I believe this
 approach would work for 95% of all functions in lib389. Another benefit is 
 that
 unit tests are much faster, than on real DS instance.

 Sidenote: even though everything is defined in separate namespace of 'repl'
 module as function, in runtime they can be used as normal methods of class
 DSInstance. That is handled by DSModuleProxy. We already went through this, 
 but
 not with Roberto.

 Hopefully, now with some code in our hands, we will be able to understand 
 each
 other on this 'mocking' issue and come to conclusions more quickly.

 Let me know what you think.

 Thank you,
 Jan
 
--
389-devel mailing list
389-de...@lists.fedoraproject.org
https://admin.fedoraproject.org/mailman/listinfo/389-devel

Re: [389-devel] Proof of concept: mocking DS in lib389

2013-10-29 Thread Jan Rusnacko
On 10/28/2013 02:52 PM, Roberto Polli wrote:
 Hi @all,
 
 Jan wrote:
 as I promised, I am sending you a proof-of-concept code that
 demonstrates, how we can mock DS in unit tests for library function
 Ok, that's clear.
 
 instead of sending command to real DS instance,
 they just store the data in 'dit' dictionary
 We could use some monkeypatching lib. 
 https://pypi.python.org/pypi/fakeldap/0.5.1
You are correct, we could ! That was Thierry`s question - we can rewrite
ldapadd,.. methods of DSInstance (monkeypatching), OR define MockDS class with
fake ldapadd,.. and use that one.
 
 Now I can successfully test that enable_changelog really works,
 _really_ is not the right word, right :
I think it is. The unit test for enable_changelog really does test the code of
enable_changelog(). It does not test ldapadd, ldapmodify ... methods (that
should be a job for ldapadd`s unit test) and it does not test how real 389 DS
would respond to such request (that is job for 389 DS acceptance, or as you
refer to them, integration tests).

It is a unit test.
 
 this approach would work for 95% of all functions in lib389.
 I agree that many functions are just ADD/DELETE, and this will work for that.
 
 Mocking functions involving MOD, default values, simulating errors  co will 
 be complex though: that's the reason why - even after adding unit tests - I 

 will leave the integration testings in the same repo.
They will be part of 389-ds-base repo. If we want to keep them together with
lib389, then lib389 would be merged to 389-ds-base repo. That`s where developers
would like to keep these.
 
 DSInstance. That is handled by DSModuleProxy. We already went through
 this, but not with Roberto.
 Saw the code, it just imports all files in the folder, right? It's a nice 
 trick, even if it makes the design a bit complex.
Correct ! Takes functions from modules and makes them methods of DSInstance.
 
 Peace,
 R.
 
 
--
389-devel mailing list
389-de...@lists.fedoraproject.org
https://admin.fedoraproject.org/mailman/listinfo/389-devel

Re: [389-devel] Proof of concept: mocking DS in lib389

2013-10-29 Thread Jan Rusnacko
On 10/29/2013 03:30 PM, thierry bordaz wrote:
 On 10/29/2013 02:18 PM, Jan Rusnacko wrote:
 Hello Thierry,

 I am not rewriting ldapadd,...  methods of real DS class, I am in fact
 creating MockDS class with custom ldapadd,... methods, _just_ like you 
 suggest :)

 Furthermore, you can view it as a subclass of real_ds - even though it is 
 not
 a proper Python subclass, it inherits all functions from repl module just 
 like
 real_ds would (again through ModuleProxy mechanism). So, methods that are
 defined in repl are the same for real_ds class and for MockDS class, but
 ldap.. methods are different. So, basically exactly what you suggest :)
 
 Hi Jan,
 
 Sorry my question was not clear. For example an other approach could be
 
 Class DSInstance (object):
 def __init__(self):
 ...
   
 def ldapadd_r(self, input):
 # real call to pythonldap.add_s
 
 Class MockDSInstance(DSInstance):
 def __init__(self):
 ...
 
 def ldapadd_r(self, input):
 input = input.strip()
 entry = dict(e.strip().split(': ') for e in input.split('\n'))
 self.dit[entry['dn']] = entry
 
 

 My understanding is that both approach would allow us to call inherited
 methods, just ldap method are different.
 What are the advantages of the approach you described compare to the one 
 above ?
Oh, ok. Not sure what would be advantage/disadvantage. Result of both approaches
is basically the same ... We could do it this way too.
 
 best regards
 thierry

 Code of the whole class along with all methods is in file
 tests/test_dsmodules/conftest.py line 7.

 Thank you,
 Jan

 On 10/28/2013 12:02 PM, thierry bordaz wrote:
 Hi Jan,

 That is very impressive POC, far above my skill in python. Thanks for
 sharing this.
 I have a novice question.
 This implementation overwrites the basic ldapadd,ldapsearch... function 
 of
 the real DS.
 An other approach is to write a 'mock_ds' class being a subclass of
 'real_ds' and to overwrite the ldapadd,ldapsearch in mock_ds class (to 
 store
 data into a dict). What would be the advantages of your approach ?

 best regards
 thierry

 On 10/25/2013 09:36 PM, Jan Rusnacko wrote:
 Hello Roberto and Thierry,

 as I promised, I am sending you a proof-of-concept code that demonstrates, 
 how
 we can mock DS in unit tests for library function (see attachment). You 
 can run
 tests just by executing py.test in tests directory.

 Only 3 files are of interest here:

 lib389/dsmodules/repl.py - this is a Python module with functions - they 
 expect
 DS instance as the first argument. Since they are functions, not methods, 
 I can
 just mock DS and pass that fake one as the first argument to them in unit 
 tests.

 tests/test_dsmodules/conftest.py - this file contains definition of mock DS
 class along with py.test fixture, that returns it.

 tests/test_dsmodules/test_repl.py - this contains unit tests for functions 
 from
 repl.py.

 What I do is quite simple - I override ldapadd, ldapdelete .. methods of 
 mock DS
 class, so that instead of sending command to real DS instance, they just 
 store
 the data in 'dit' dictionary (which represents content stored in DS). This 
 way,
 I can check that when I call e.g. function enable_changelog(..), in the 
 end DS
 will have correct changelog entry.

 To put it very bluntly - enable_changelog(..) function just adds correct
 changelog entry to whatever is passed to it as the first argument. In unit
 tests, it is mock DS, otherwise it would be real DS class that sends real 
 ldap
 commands to real DS instance behind.

 Now I can successfully test that enable_changelog really works, without 
 going
 into trouble defining DSInstance or ldap calls at all. Also, I believe this
 approach would work for 95% of all functions in lib389. Another benefit is 
 that
 unit tests are much faster, than on real DS instance.

 Sidenote: even though everything is defined in separate namespace of 'repl'
 module as function, in runtime they can be used as normal methods of class
 DSInstance. That is handled by DSModuleProxy. We already went through 
 this, but
 not with Roberto.

 Hopefully, now with some code in our hands, we will be able to understand 
 each
 other on this 'mocking' issue and come to conclusions more quickly.

 Let me know what you think.

 Thank you,
 Jan
 
--
389-devel mailing list
389-de...@lists.fedoraproject.org
https://admin.fedoraproject.org/mailman/listinfo/389-devel

Re: [389-devel] Proof of concept: mocking DS in lib389

2013-10-29 Thread thierry bordaz

On 10/29/2013 02:18 PM, Jan Rusnacko wrote:

Hello Thierry,

I am not rewriting ldapadd,...  methods of real DS class, I am in fact
creating MockDS class with custom ldapadd,... methods, _just_ like you suggest 
:)

Furthermore, you can view it as a subclass of real_ds - even though it is not
a proper Python subclass, it inherits all functions from repl module just like
real_ds would (again through ModuleProxy mechanism). So, methods that are
defined in repl are the same for real_ds class and for MockDS class, but
ldap.. methods are different. So, basically exactly what you suggest :)


Hi Jan,

   Sorry my question was not clear. For example an other approach could be

   Class DSInstance (object):
def __init__(self):
...

def ldapadd_r(self, input):
# real call to pythonldap.add_s

   Class MockDSInstance(DSInstance):
def __init__(self):
...

def ldapadd_r(self, input):
input = input.strip()
entry = dict(e.strip().split(': ') for e in
   input.split('\n'))
self.dit[entry['dn']] = entry



   My understanding is that both approach would allow us to call
   inherited methods, just ldap method are different.
   What are the advantages of the approach you described compare to the
   one above ?

best regards
thierry


Code of the whole class along with all methods is in file
tests/test_dsmodules/conftest.py line 7.

Thank you,
Jan

On 10/28/2013 12:02 PM, thierry bordaz wrote:

Hi Jan,

 That is very impressive POC, far above my skill in python. Thanks for
 sharing this.
 I have a novice question.
 This implementation overwrites the basic ldapadd,ldapsearch... function of
 the real DS.
 An other approach is to write a 'mock_ds' class being a subclass of
 'real_ds' and to overwrite the ldapadd,ldapsearch in mock_ds class (to 
store
 data into a dict). What would be the advantages of your approach ?

best regards
thierry

On 10/25/2013 09:36 PM, Jan Rusnacko wrote:

Hello Roberto and Thierry,

as I promised, I am sending you a proof-of-concept code that demonstrates, how
we can mock DS in unit tests for library function (see attachment). You can run
tests just by executing py.test in tests directory.

Only 3 files are of interest here:

lib389/dsmodules/repl.py - this is a Python module with functions - they expect
DS instance as the first argument. Since they are functions, not methods, I can
just mock DS and pass that fake one as the first argument to them in unit tests.

tests/test_dsmodules/conftest.py - this file contains definition of mock DS
class along with py.test fixture, that returns it.

tests/test_dsmodules/test_repl.py - this contains unit tests for functions from
repl.py.

What I do is quite simple - I override ldapadd, ldapdelete .. methods of mock DS
class, so that instead of sending command to real DS instance, they just store
the data in 'dit' dictionary (which represents content stored in DS). This way,
I can check that when I call e.g. function enable_changelog(..), in the end DS
will have correct changelog entry.

To put it very bluntly - enable_changelog(..) function just adds correct
changelog entry to whatever is passed to it as the first argument. In unit
tests, it is mock DS, otherwise it would be real DS class that sends real ldap
commands to real DS instance behind.

Now I can successfully test that enable_changelog really works, without going
into trouble defining DSInstance or ldap calls at all. Also, I believe this
approach would work for 95% of all functions in lib389. Another benefit is that
unit tests are much faster, than on real DS instance.

Sidenote: even though everything is defined in separate namespace of 'repl'
module as function, in runtime they can be used as normal methods of class
DSInstance. That is handled by DSModuleProxy. We already went through this, but
not with Roberto.

Hopefully, now with some code in our hands, we will be able to understand each
other on this 'mocking' issue and come to conclusions more quickly.

Let me know what you think.

Thank you,
Jan


--
389-devel mailing list
389-de...@lists.fedoraproject.org
https://admin.fedoraproject.org/mailman/listinfo/389-devel

Re: [389-devel] Proof of concept: mocking DS in lib389

2013-10-29 Thread Jan Rusnacko
On 10/28/2013 02:31 PM, Rich Megginson wrote:
 On 10/26/2013 12:49 AM, Jan Rusnacko wrote:
 On 10/25/2013 11:00 PM, Rich Megginson wrote:
 On 10/25/2013 01:36 PM, Jan Rusnacko wrote:
 Hello Roberto and Thierry,

 as I promised, I am sending you a proof-of-concept code that demonstrates, 
 how
 we can mock DS in unit tests for library function (see attachment). You 
 can run
 tests just by executing py.test in tests directory.

 Only 3 files are of interest here:

 lib389/dsmodules/repl.py - this is a Python module with functions - they 
 expect
 DS instance as the first argument. Since they are functions, not methods, 
 I can
 just mock DS and pass that fake one as the first argument to them in unit
 tests.

 tests/test_dsmodules/conftest.py - this file contains definition of mock DS
 class along with py.test fixture, that returns it.

 tests/test_dsmodules/test_repl.py - this contains unit tests for functions 
 from
 repl.py.

 What I do is quite simple - I override ldapadd, ldapdelete .. methods of
 mock DS
 class, so that instead of sending command to real DS instance, they just 
 store
 the data in 'dit' dictionary (which represents content stored in DS). This 
 way,
 I can check that when I call e.g. function enable_changelog(..), in the 
 end DS
 will have correct changelog entry.

 To put it very bluntly - enable_changelog(..) function just adds correct
 changelog entry to whatever is passed to it as the first argument. In unit
 tests, it is mock DS, otherwise it would be real DS class that sends real 
 ldap
 commands to real DS instance behind.
 def test_add_repl_manager(fake_ds_inst_with_repl):
  ds_inst = fake_ds_inst_with_repl
  ds_inst.repl.add_repl_manager(cn=replication manager, cn=config,
 Secret123)
  assert ds_inst.dit[cn=replication manager, 
 cn=config][userPassword] ==
 Secret123
  assert ds_inst.dit[cn=replication manager, 
 cn=config][nsIdleTimeout]
 == 0
  assert ds_inst.dit[cn=replication manager, cn=config][cn] ==
 replication manager

 If you are using a real directory server instance, doing add_repl_manager() 
 is
 going to make a real LDAP ADD request, right?
 Correct. If you pass DS with real ldapadd method that makes real reqests, its
 going to use that.
 Will it still update the ds_inst.dit dict?
 ds_inst.dit is updated in mocked ldapadd. So in real ldapadd, no.
 Wouldn't you have to do a real LDAP Search request to get the
 actual values?
 Yes, correct. ds_inst.dit[] .. call is specific to mocked DS.

 But you are right - I could add fake ldapsearch method, that would return
 entries from 'dit' dictionary and use that to retrieve entries from mocked 
 DS.
 
 Because, otherwise, you have separate tests for mock DS and real DS?  Or 
 perhaps
 I'm missing something?
I dont understand the question, but let me answer something :)

Class DSInstance would have ~10 methods that make real requests to real DS
instance (setup, remove, ldapadd, ldapmodify, .., start, stop ..). All other
methods would probably depend on ldapadd, ldapmodify..

We can tests these 10 methods either using real DS, or somehow faking the
traffic, or just review them manually .. As for other 95 % of library functions
that depend on those, we can use MockDS with fake ldapadd, ldapmodify to make
unit tests. These unit tests will verify that *assuming* they receive OK
ldapmodify method, they will use it to perform correct calls to set up the thing
they are supposed to.

To be concrete, unit test above, test_add_repl_manager(fake_ds_inst_with_repl),
verifies that method ds_inst.repl.add_repl_manager() will add replication
manager with expected fields using ldapadd method of object that was passed to
it. It will *not* verify the correctness of ldapadd method of real DSInstance
class (that is the job of ldapadd`s unit test), nor will it verify that real DS
instance would accept such call or behave correctly (that is the job of DS
acceptance tests). Hence, a unit test.
 
 Now I can successfully test that enable_changelog really works, without 
 going
 into trouble defining DSInstance or ldap calls at all. Also, I believe this
 approach would work for 95% of all functions in lib389. Another benefit is 
 that
 unit tests are much faster, than on real DS instance.

 Sidenote: even though everything is defined in separate namespace of 'repl'
 module as function, in runtime they can be used as normal methods of class
 DSInstance. That is handled by DSModuleProxy. We already went through 
 this, but
 not with Roberto.

 Hopefully, now with some code in our hands, we will be able to understand 
 each
 other on this 'mocking' issue and come to conclusions more quickly.

 Let me know what you think.

 Thank you,
 Jan
 
--
389-devel mailing list
389-devel@lists.fedoraproject.org
https://admin.fedoraproject.org/mailman/listinfo/389-devel

Re: [389-devel] Proof of concept: mocking DS in lib389

2013-10-29 Thread Roberto Polli
Hi @all,

Jan wrote:
 I am in fact
 creating MockDS class with custom ldapadd,
actually I agree with Jan about how the mocking process works:
 1- reuse/create an ldap mocking class;
 2- rewire existing tests on the mock;

 Hence, a unit test.
Ok, I agree to add unit-testing. Just I don't want to move integration tests 
(the one against a real instance) in another repo.
I'd leave the integration tests there so that whenever somebody clones he can 
test if the lib works for his installation.

 It will *not* verify the correctness of ldapadd method of real DSInstance
class (that is the job of ldapadd`s unit test
About testing ldapadd  co, we should consider that - as of now - lib389 wraps 
some python-ldap methods with *args, **kwds. 
We should even be more consistent in parameter names between wrapping and 
wrapped method .

Peace,
R.



On Tuesday 29 October 2013 14:18:59 Jan Rusnacko wrote:
 Hello Thierry,
 
 I am not rewriting ldapadd,...  methods of real DS class, I am in fact
 creating MockDS class with custom ldapadd,... methods, _just_ like you
 suggest :)
 
 Furthermore, you can view it as a subclass of real_ds - even though it is
 not a proper Python subclass, it inherits all functions from repl module
 just like real_ds would (again through ModuleProxy mechanism). So,
 methods that are defined in repl are the same for real_ds class and for
 MockDS class, but ldap.. methods are different. So, basically exactly what
 you suggest :)
 
 Code of the whole class along with all methods is in file
 tests/test_dsmodules/conftest.py line 7.
 
 Thank you,
 Jan
 
 On 10/28/2013 12:02 PM, thierry bordaz wrote:
  Hi Jan,
  
  That is very impressive POC, far above my skill in python. Thanks for
  sharing this.
  I have a novice question.
  This implementation overwrites the basic ldapadd,ldapsearch...
  function of
  the real DS.
  An other approach is to write a 'mock_ds' class being a subclass of
  'real_ds' and to overwrite the ldapadd,ldapsearch in mock_ds class (to
  store data into a dict). What would be the advantages of your
  approach ? 
  best regards
  thierry
  
  On 10/25/2013 09:36 PM, Jan Rusnacko wrote:
  Hello Roberto and Thierry,
  
  as I promised, I am sending you a proof-of-concept code that
  demonstrates, how we can mock DS in unit tests for library function (see
  attachment). You can run tests just by executing py.test in tests
  directory.
  
  Only 3 files are of interest here:
  
  lib389/dsmodules/repl.py - this is a Python module with functions - they
  expect DS instance as the first argument. Since they are functions, not
  methods, I can just mock DS and pass that fake one as the first argument
  to them in unit tests.
  
  tests/test_dsmodules/conftest.py - this file contains definition of mock
  DS
  class along with py.test fixture, that returns it.
  
  tests/test_dsmodules/test_repl.py - this contains unit tests for
  functions from repl.py.
  
  What I do is quite simple - I override ldapadd, ldapdelete .. methods of
  mock DS class, so that instead of sending command to real DS instance,
  they just store the data in 'dit' dictionary (which represents content
  stored in DS). This way, I can check that when I call e.g. function
  enable_changelog(..), in the end DS will have correct changelog entry.
  
  To put it very bluntly - enable_changelog(..) function just adds correct
  changelog entry to whatever is passed to it as the first argument. In
  unit
  tests, it is mock DS, otherwise it would be real DS class that sends real
  ldap commands to real DS instance behind.
  
  Now I can successfully test that enable_changelog really works, without
  going into trouble defining DSInstance or ldap calls at all. Also, I
  believe this approach would work for 95% of all functions in lib389.
  Another benefit is that unit tests are much faster, than on real DS
  instance.
  
  Sidenote: even though everything is defined in separate namespace of
  'repl'
  module as function, in runtime they can be used as normal methods of
  class
  DSInstance. That is handled by DSModuleProxy. We already went through
  this, but not with Roberto.
  
  Hopefully, now with some code in our hands, we will be able to understand
  each other on this 'mocking' issue and come to conclusions more quickly.
  
  Let me know what you think.
  
  Thank you,
  Jan

-- 
Roberto Polli
Community Manager
Babel S.r.l. - http://www.babel.it
T: +39.06.9826.9651 M: +39.340.652.2736 F: +39.06.9826.9680
P.zza S.Benedetto da Norcia, 33 - 00040 Pomezia (Roma)

CONFIDENZIALE: Questo messaggio ed i suoi allegati sono di carattere 
confidenziale per i destinatari in indirizzo.
E' vietato l'inoltro non autorizzato a destinatari diversi da quelli indicati 
nel messaggio originale.
Se ricevuto per errore, l'uso del contenuto e' proibito; si prega di 
comunicarlo al mittente e cancellarlo immediatamente.
--
389-devel mailing list
389-devel@lists.fedoraproject.org

Re: [389-devel] Proof of concept: mocking DS in lib389

2013-10-28 Thread Rich Megginson

On 10/26/2013 12:49 AM, Jan Rusnacko wrote:

On 10/25/2013 11:00 PM, Rich Megginson wrote:

On 10/25/2013 01:36 PM, Jan Rusnacko wrote:

Hello Roberto and Thierry,

as I promised, I am sending you a proof-of-concept code that demonstrates, how
we can mock DS in unit tests for library function (see attachment). You can run
tests just by executing py.test in tests directory.

Only 3 files are of interest here:

lib389/dsmodules/repl.py - this is a Python module with functions - they expect
DS instance as the first argument. Since they are functions, not methods, I can
just mock DS and pass that fake one as the first argument to them in unit tests.

tests/test_dsmodules/conftest.py - this file contains definition of mock DS
class along with py.test fixture, that returns it.

tests/test_dsmodules/test_repl.py - this contains unit tests for functions from
repl.py.

What I do is quite simple - I override ldapadd, ldapdelete .. methods of mock DS
class, so that instead of sending command to real DS instance, they just store
the data in 'dit' dictionary (which represents content stored in DS). This way,
I can check that when I call e.g. function enable_changelog(..), in the end DS
will have correct changelog entry.

To put it very bluntly - enable_changelog(..) function just adds correct
changelog entry to whatever is passed to it as the first argument. In unit
tests, it is mock DS, otherwise it would be real DS class that sends real ldap
commands to real DS instance behind.

def test_add_repl_manager(fake_ds_inst_with_repl):
 ds_inst = fake_ds_inst_with_repl
 ds_inst.repl.add_repl_manager(cn=replication manager, cn=config, 
Secret123)
 assert ds_inst.dit[cn=replication manager, cn=config][userPassword] ==
Secret123
 assert ds_inst.dit[cn=replication manager, cn=config][nsIdleTimeout] == 
0
 assert ds_inst.dit[cn=replication manager, cn=config][cn] ==
replication manager

If you are using a real directory server instance, doing add_repl_manager() is
going to make a real LDAP ADD request, right?

Correct. If you pass DS with real ldapadd method that makes real reqests, its
going to use that.

Will it still update the ds_inst.dit dict?

ds_inst.dit is updated in mocked ldapadd. So in real ldapadd, no.

Wouldn't you have to do a real LDAP Search request to get the
actual values?

Yes, correct. ds_inst.dit[] .. call is specific to mocked DS.

But you are right - I could add fake ldapsearch method, that would return
entries from 'dit' dictionary and use that to retrieve entries from mocked DS.


Because, otherwise, you have separate tests for mock DS and real DS?  Or 
perhaps I'm missing something?



Now I can successfully test that enable_changelog really works, without going
into trouble defining DSInstance or ldap calls at all. Also, I believe this
approach would work for 95% of all functions in lib389. Another benefit is that
unit tests are much faster, than on real DS instance.

Sidenote: even though everything is defined in separate namespace of 'repl'
module as function, in runtime they can be used as normal methods of class
DSInstance. That is handled by DSModuleProxy. We already went through this, but
not with Roberto.

Hopefully, now with some code in our hands, we will be able to understand each
other on this 'mocking' issue and come to conclusions more quickly.

Let me know what you think.

Thank you,
Jan


--
389-devel mailing list
389-devel@lists.fedoraproject.org
https://admin.fedoraproject.org/mailman/listinfo/389-devel

Re: [389-devel] Proof of concept: mocking DS in lib389

2013-10-28 Thread Roberto Polli
Hi @all,

Jan wrote:
  as I promised, I am sending you a proof-of-concept code that
  demonstrates, how we can mock DS in unit tests for library function
Ok, that's clear.

  instead of sending command to real DS instance,
  they just store the data in 'dit' dictionary
We could use some monkeypatching lib. 
https://pypi.python.org/pypi/fakeldap/0.5.1

  Now I can successfully test that enable_changelog really works,
_really_ is not the right word, right :

  this approach would work for 95% of all functions in lib389.
I agree that many functions are just ADD/DELETE, and this will work for that.

Mocking functions involving MOD, default values, simulating errors  co will 
be complex though: that's the reason why - even after adding unit tests - I 
will leave the integration testings in the same repo.

  DSInstance. That is handled by DSModuleProxy. We already went through
  this, but not with Roberto.
Saw the code, it just imports all files in the folder, right? It's a nice 
trick, even if it makes the design a bit complex.

Peace,
R.


-- 
Roberto Polli
Community Manager
Babel S.r.l. - http://www.babel.it
T: +39.06.9826.9651 M: +39.340.652.2736 F: +39.06.9826.9680
P.zza S.Benedetto da Norcia, 33 - 00040 Pomezia (Roma)

CONFIDENZIALE: Questo messaggio ed i suoi allegati sono di carattere 
confidenziale per i destinatari in indirizzo.
E' vietato l'inoltro non autorizzato a destinatari diversi da quelli indicati 
nel messaggio originale.
Se ricevuto per errore, l'uso del contenuto e' proibito; si prega di 
comunicarlo al mittente e cancellarlo immediatamente.
--
389-devel mailing list
389-devel@lists.fedoraproject.org
https://admin.fedoraproject.org/mailman/listinfo/389-devel

Re: [389-devel] Proof of concept: mocking DS in lib389

2013-10-26 Thread Jan Rusnacko
On 10/25/2013 11:00 PM, Rich Megginson wrote:
 On 10/25/2013 01:36 PM, Jan Rusnacko wrote:
 Hello Roberto and Thierry,

 as I promised, I am sending you a proof-of-concept code that demonstrates, 
 how
 we can mock DS in unit tests for library function (see attachment). You can 
 run
 tests just by executing py.test in tests directory.

 Only 3 files are of interest here:

 lib389/dsmodules/repl.py - this is a Python module with functions - they 
 expect
 DS instance as the first argument. Since they are functions, not methods, I 
 can
 just mock DS and pass that fake one as the first argument to them in unit 
 tests.

 tests/test_dsmodules/conftest.py - this file contains definition of mock DS
 class along with py.test fixture, that returns it.

 tests/test_dsmodules/test_repl.py - this contains unit tests for functions 
 from
 repl.py.

 What I do is quite simple - I override ldapadd, ldapdelete .. methods of 
 mock DS
 class, so that instead of sending command to real DS instance, they just 
 store
 the data in 'dit' dictionary (which represents content stored in DS). This 
 way,
 I can check that when I call e.g. function enable_changelog(..), in the end 
 DS
 will have correct changelog entry.

 To put it very bluntly - enable_changelog(..) function just adds correct
 changelog entry to whatever is passed to it as the first argument. In unit
 tests, it is mock DS, otherwise it would be real DS class that sends real 
 ldap
 commands to real DS instance behind.
 def test_add_repl_manager(fake_ds_inst_with_repl):
 ds_inst = fake_ds_inst_with_repl
 ds_inst.repl.add_repl_manager(cn=replication manager, cn=config, 
 Secret123)
 assert ds_inst.dit[cn=replication manager, cn=config][userPassword] ==
 Secret123
 assert ds_inst.dit[cn=replication manager, cn=config][nsIdleTimeout] 
 == 0
 assert ds_inst.dit[cn=replication manager, cn=config][cn] ==
 replication manager
 
 If you are using a real directory server instance, doing add_repl_manager() is
 going to make a real LDAP ADD request, right?
Correct. If you pass DS with real ldapadd method that makes real reqests, its
going to use that.
 Will it still update the ds_inst.dit dict? 
ds_inst.dit is updated in mocked ldapadd. So in real ldapadd, no.
 Wouldn't you have to do a real LDAP Search request to get the
 actual values?
Yes, correct. ds_inst.dit[] .. call is specific to mocked DS.

But you are right - I could add fake ldapsearch method, that would return
entries from 'dit' dictionary and use that to retrieve entries from mocked DS.
 

 Now I can successfully test that enable_changelog really works, without going
 into trouble defining DSInstance or ldap calls at all. Also, I believe this
 approach would work for 95% of all functions in lib389. Another benefit is 
 that
 unit tests are much faster, than on real DS instance.

 Sidenote: even though everything is defined in separate namespace of 'repl'
 module as function, in runtime they can be used as normal methods of class
 DSInstance. That is handled by DSModuleProxy. We already went through this, 
 but
 not with Roberto.

 Hopefully, now with some code in our hands, we will be able to understand 
 each
 other on this 'mocking' issue and come to conclusions more quickly.

 Let me know what you think.

 Thank you,
 Jan
 
--
389-devel mailing list
389-devel@lists.fedoraproject.org
https://admin.fedoraproject.org/mailman/listinfo/389-devel

Re: [389-devel] Proof of concept: mocking DS in lib389

2013-10-25 Thread Rich Megginson

On 10/25/2013 01:36 PM, Jan Rusnacko wrote:

Hello Roberto and Thierry,

as I promised, I am sending you a proof-of-concept code that demonstrates, how
we can mock DS in unit tests for library function (see attachment). You can run
tests just by executing py.test in tests directory.

Only 3 files are of interest here:

lib389/dsmodules/repl.py - this is a Python module with functions - they expect
DS instance as the first argument. Since they are functions, not methods, I can
just mock DS and pass that fake one as the first argument to them in unit tests.

tests/test_dsmodules/conftest.py - this file contains definition of mock DS
class along with py.test fixture, that returns it.

tests/test_dsmodules/test_repl.py - this contains unit tests for functions from
repl.py.

What I do is quite simple - I override ldapadd, ldapdelete .. methods of mock DS
class, so that instead of sending command to real DS instance, they just store
the data in 'dit' dictionary (which represents content stored in DS). This way,
I can check that when I call e.g. function enable_changelog(..), in the end DS
will have correct changelog entry.

To put it very bluntly - enable_changelog(..) function just adds correct
changelog entry to whatever is passed to it as the first argument. In unit
tests, it is mock DS, otherwise it would be real DS class that sends real ldap
commands to real DS instance behind.

def test_add_repl_manager(fake_ds_inst_with_repl):
ds_inst = fake_ds_inst_with_repl
ds_inst.repl.add_repl_manager(cn=replication manager, cn=config, 
Secret123)
assert ds_inst.dit[cn=replication manager, 
cn=config][userPassword] == Secret123
assert ds_inst.dit[cn=replication manager, 
cn=config][nsIdleTimeout] == 0
assert ds_inst.dit[cn=replication manager, cn=config][cn] == 
replication manager


If you are using a real directory server instance, doing 
add_repl_manager() is going to make a real LDAP ADD request, right? Will 
it still update the ds_inst.dit dict?  Wouldn't you have to do a real 
LDAP Search request to get the actual values?




Now I can successfully test that enable_changelog really works, without going
into trouble defining DSInstance or ldap calls at all. Also, I believe this
approach would work for 95% of all functions in lib389. Another benefit is that
unit tests are much faster, than on real DS instance.

Sidenote: even though everything is defined in separate namespace of 'repl'
module as function, in runtime they can be used as normal methods of class
DSInstance. That is handled by DSModuleProxy. We already went through this, but
not with Roberto.

Hopefully, now with some code in our hands, we will be able to understand each
other on this 'mocking' issue and come to conclusions more quickly.

Let me know what you think.

Thank you,
Jan


--
389-devel mailing list
389-de...@lists.fedoraproject.org
https://admin.fedoraproject.org/mailman/listinfo/389-devel

[389-devel] Proof of concept: mocking DS in lib389

2013-10-25 Thread Jan Rusnacko
Hello Roberto and Thierry,

as I promised, I am sending you a proof-of-concept code that demonstrates, how
we can mock DS in unit tests for library function (see attachment). You can run
tests just by executing py.test in tests directory.

Only 3 files are of interest here:

lib389/dsmodules/repl.py - this is a Python module with functions - they expect
DS instance as the first argument. Since they are functions, not methods, I can
just mock DS and pass that fake one as the first argument to them in unit tests.

tests/test_dsmodules/conftest.py - this file contains definition of mock DS
class along with py.test fixture, that returns it.

tests/test_dsmodules/test_repl.py - this contains unit tests for functions from
repl.py.

What I do is quite simple - I override ldapadd, ldapdelete .. methods of mock DS
class, so that instead of sending command to real DS instance, they just store
the data in 'dit' dictionary (which represents content stored in DS). This way,
I can check that when I call e.g. function enable_changelog(..), in the end DS
will have correct changelog entry.

To put it very bluntly - enable_changelog(..) function just adds correct
changelog entry to whatever is passed to it as the first argument. In unit
tests, it is mock DS, otherwise it would be real DS class that sends real ldap
commands to real DS instance behind.

Now I can successfully test that enable_changelog really works, without going
into trouble defining DSInstance or ldap calls at all. Also, I believe this
approach would work for 95% of all functions in lib389. Another benefit is that
unit tests are much faster, than on real DS instance.

Sidenote: even though everything is defined in separate namespace of 'repl'
module as function, in runtime they can be used as normal methods of class
DSInstance. That is handled by DSModuleProxy. We already went through this, but
not with Roberto.

Hopefully, now with some code in our hands, we will be able to understand each
other on this 'mocking' issue and come to conclusions more quickly.

Let me know what you think.

Thank you,
Jan


proof_of_concept_mocking.tar.gz
Description: GNU Zip compressed data
--
389-devel mailing list
389-devel@lists.fedoraproject.org
https://admin.fedoraproject.org/mailman/listinfo/389-devel