On Apr 8, 2014, at 3:04 PM, Jamie Lennox 
<jamielen...@redhat.com<mailto:jamielen...@redhat.com>> wrote:



----- Original Message -----
From: "Paul Michali (pcm)" <p...@cisco.com<mailto:p...@cisco.com>>
To: "OpenStack Development Mailing List (not for usage questions)" 
<openstack-dev@lists.openstack.org<mailto:openstack-dev@lists.openstack.org>>
Cc: jamielen...@gmail.com<mailto:jamielen...@gmail.com>
Sent: Wednesday, April 9, 2014 12:09:58 AM
Subject: [openstack-dev] [infra]Requesting consideration of httmock package for 
test-requirements in Juno

Reposting this, after discussing with Sean Dague…

For background, I have developed a REST client lib to talk to a H/W device
with REST server for VPNaaS in Neutron. To support unit testing of this, I
created a UT module and a mock REST server module and used the httmock
package. I found it easy to use, and was able to easily create a sub-class
of my UT to run the same test cases with real H/W, instead of the mock REST
server. See the original email below, for links of the UT and REST mock to
see how I used it.


I created a bug under requirements, to propose adding httmock to the
test-requirements. Sean mentioned that there is an existing mock package,
called httpretty , which I found is used in keystone client UTs), and should
petition to see if httmock should replace httpretty, since the two appear to
overlap in functionality.

I found this link, with a brief comparison of the two:
http://marekbrzoska.wordpress.com/2013/08/28/mocking-http-requests-in-python/

So… I’m wondering if the community is interested in adopting this package
(with the goal of deprecating the httpretty package). Otherwise, I will work
on reworking the UT code I have to try to use httpretty.

Would be interested in peoples’ thoughts, especially those who have worked
with httpretty.

Thanks in advance!

So I introduced HTTPretty into the requirements and did the work around 
keystoneclient and am well aware that it has a few warts.

PCM: Great, I grabbed your name from keystone client logs and was hoping you 
had some knowledge of httpretty.



At the time we were going through the changeover from httplib to requests and 
httpretty gave a good way to change over the library and ensure that we hadn't 
actually changed the issued requests at all. If we had already been on requests 
i don't know if i'd have made the same choice.

In general I am in favour of mocking the response layer rather than the client 
layer - whether we do this with httpretty or httmock doesn't bother me that 
much. Honestly I don't think a global patch of the requests Session object is 
that much safer that a global patch of the socket interface, if anything 
requests is under development and so this interface is less defined.

PCM: Not sure that httmock can be considered a global patch. It is a context 
lib that intercepts the call through various decorators where the request can 
be filtered/processed and if not, will fall through and call the actual library.

So, with the context lib, you can define several handlers for the request(s). 
When the call is made, it will try each handler and if they all return None, 
will call the original function, otherwise they return the value of the mock 
routine.  Here’s an example front he test cases I cerated:

        with httmock.HTTMock(csr_request.token, csr_request.put,
                             csr_request.normal_get):
            keepalive_info = {'interval': 60, 'retry': 4}
            self.csr.configure_ike_keepalive(keepalive_info)
            self.assertEqual(requests.codes.NO_CONTENT, self.csr.status)
            content = self.csr.get_request('vpn-svc/ike/keepalive')
            self.assertEqual(requests.codes.OK, self.csr.status)
            expected = {'periodic': False}
            expected.update(keepalive_info)
            self.assertDictContainsSubset(expected, content)

The client code (red) does a POST with authentication info to get token, does a 
PUT with the setting, and then a GET to verify the value. The mock module has 
these methods created:

@httmock.urlmatch(netloc=r'localhost')
def token(url, request):
    if 'auth/token-services' in url.path:
        return {'status_code': requests.codes.OK,
                'content': {'token-id': 'dummy-token'}}


@httmock.urlmatch(netloc=r'localhost')
def normal_get(url, request):
    if request.method != 'GET':
        return
    if not request.headers.get('X-auth-token', None):
        return {'status_code': requests.codes.UNAUTHORIZED}
…
    if 'vpn-svc/ike/keepalive' in url.path:
        content = {u'interval': 60,
                   u'retry': 4,
                   u'periodic': True}
        return httmock.response(requests.codes.OK, content=content)

@httmock.urlmatch(netloc=r'localhost')
def put(url, request):
    if request.method != 'PUT':
        return
    if not request.headers.get('X-auth-token', None):
        return {'status_code': requests.codes.UNAUTHORIZED}
    return {'status_code': requests.codes.NO_CONTENT}


Just a few notes….
A)  Could have created separate context lib for put vs get.
B)  Could have a method for specific URI request matches (I do that in some 
places, in others I catch all requests).
C)  Can filter the requests based on request type or URI.
D)  Can catch all URLs or filter.
E)  Additional decorators can be created for these handlers.
F)  There is lots of flexibility with manipulating the response data.

For (C) I’ve done things like this:

@filter_request(['post'], 'vpn-svc/site-to-site')
@httmock.urlmatch(netloc=r'localhost')
def post_missing_ipsec_policy(url, request):
    if not request.headers.get('X-auth-token', None):
        return {'status_code': requests.codes.UNAUTHORIZED}
    return {'status_code': requests.codes.BAD_REQUEST}

For (D), I have all my handlers set for localhost, and then I have another test 
module that creates a subclass of the test class, sets the host to an IP of a 
live system, and runs the same tests, only this time against a live router, 
instead the mock module. This saves a lot of coding and allows me to reuse the 
test code (and make sure it REALLY works with real hardware, in my case).

For (E), I did this to simulate a timeout in a request and then latter success 
on retry:

@filter_request(['get'], 'global/host-name')
@repeat(1)
@httmock.urlmatch(netloc=r'localhost')
def expired_request(url, request):
    """Simulate access denied failure on first request for this resource.

    Intent here is to simulate that the token has expired, by failing
    the first request to the resource. Because of the repeat=1, this
    will only be called once, and subsequent calls will not be handled
    by this function, but instead will access the normal handler and
    will pass. Currently configured for a GET request, but will work
    with POST and PUT as well. For DELETE, would need to filter_request on a
    different resource (e.g. 'global/local-users')
    """

    return {'status_code': requests.codes.UNAUTHORIZED}

Ref: 
https://github.com/openstack/neutron/blob/master/neutron/tests/unit/services/vpn/device_drivers/notest_cisco_csr_rest.py
Ref: 
https://github.com/openstack/neutron/blob/master/neutron/tests/unit/services/vpn/device_drivers/cisco_csr_mock.py



What i would like to see though is this mocking transferred into fixtures like 
in https://review.openstack.org/#/c/77961/ and have the actual choice in mock 
library hidden behind those fixtures. Is this a pattern that httmock can 
handle? or something else again?

PCM I see your point - it would be nice to be able to have the flexibility to 
swap the underlying mock libraries.  Would have to think about it more, to see 
if a common fixture can be used for httpretty and httmock. I’m not sure if they 
are different enough (one monkey patching, one using context lib) that it would 
be possible (and I don’t have a strong understanding of httpretty yet).

Would love to hear peoples’ thoughts no this.


PCM (Paul Michali)

MAIL …..…. p...@cisco.com<mailto:p...@cisco.com>
IRC ……..… pcm_ (irc.freenode.com<http://irc.freenode.com>)
TW ………... @pmichali
GPG Key … 4525ECC253E31A83
Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83





Jamie


PCM (Paul Michali)

MAIL …..…. p...@cisco.com<mailto:p...@cisco.com>
IRC ……..… pcm_ ( irc.freenode.com<http://irc.freenode.com> )
TW ………... @pmichali
GPG Key … 4525ECC253E31A83
Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83



On Apr 4, 2014, at 10:44 AM, Paul Michali (pcm) < 
p...@cisco.com<mailto:p...@cisco.com> > wrote:




I’d like to get this added to the test-requirements for Neutron. It is a very
flexible HTTP mock module that works with the Requests package. It is a
decorator that wraps the Request’s send() method and allows easy mocking of
responses, etc (w/o using a web server).

The bug is: https://bugs.launchpad.net/neutron/+bug/1282855

Initially I had requested both httmock and newer requests, but was requested
to separate them, so this is to target httmock as it is more important (to
me :) to get approval,


The review request is: https://review.openstack.org/#/c/75296/

An example of code that would use this:

https://github.com/openstack/neutron/blob/master/neutron/tests/unit/services/vpn/device_drivers/notest_cisco_csr_rest.py
https://github.com/openstack/neutron/blob/master/neutron/tests/unit/services/vpn/device_drivers/cisco_csr_mock.py

Looking forward to hearing whether or not we can include this package into
Juno.

Thanks in advance!


PCM (Paul Michali)

MAIL …..…. p...@cisco.com
IRC ……..… pcm_ ( irc.freenode.com )
TW ………... @pmichali
GPG Key … 4525ECC253E31A83
Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83



_______________________________________________
OpenStack-dev mailing list
OpenStack-dev@lists.openstack.org
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev


_______________________________________________
OpenStack-dev mailing list
OpenStack-dev@lists.openstack.org
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev


_______________________________________________
OpenStack-dev mailing list
OpenStack-dev@lists.openstack.org<mailto:OpenStack-dev@lists.openstack.org>
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev

_______________________________________________
OpenStack-dev mailing list
OpenStack-dev@lists.openstack.org
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev

Reply via email to