Bug 214484 - [webkitcorepy] Add mocks.ContextStack
Summary: [webkitcorepy] Add mocks.ContextStack
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Tools / Tests (show other bugs)
Version: Safari 13
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Jonathan Bedard
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2020-07-17 10:24 PDT by Jonathan Bedard
Modified: 2020-08-04 22:15 PDT (History)
2 users (show)

See Also:


Attachments
Patch (10.64 KB, patch)
2020-07-17 10:30 PDT, Jonathan Bedard
no flags Details | Formatted Diff | Diff
Patch (11.21 KB, patch)
2020-07-22 12:22 PDT, Jonathan Bedard
no flags Details | Formatted Diff | Diff
Patch (10.85 KB, patch)
2020-07-30 09:11 PDT, Jonathan Bedard
no flags Details | Formatted Diff | Diff
Patch (10.87 KB, patch)
2020-07-30 21:11 PDT, Jonathan Bedard
no flags Details | Formatted Diff | Diff
Patch (10.86 KB, patch)
2020-08-04 12:36 PDT, Jonathan Bedard
no flags Details | Formatted Diff | Diff
Patch (11.13 KB, patch)
2020-08-04 21:15 PDT, Jonathan Bedard
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Bedard 2020-07-17 10:24:40 PDT
Add a class which allows a context leveraging mock to stack. This is useful when mocking requests or subprocess, where a single function (or class of functions) is handling calls that are destined for different for different mock handlers.
Comment 1 Jonathan Bedard 2020-07-17 10:30:35 PDT
Created attachment 404572 [details]
Patch
Comment 2 Jonathan Bedard 2020-07-22 12:22:08 PDT
Created attachment 404948 [details]
Patch
Comment 3 Radar WebKit Bug Importer 2020-07-24 10:25:16 PDT
<rdar://problem/66060898>
Comment 4 Jonathan Bedard 2020-07-30 09:11:33 PDT
Created attachment 405576 [details]
Patch
Comment 5 Jonathan Bedard 2020-07-30 21:11:09 PDT
Created attachment 405661 [details]
Patch
Comment 6 Jonathan Bedard 2020-08-04 12:36:25 PDT
Created attachment 405936 [details]
Patch
Comment 7 dewei_zhu 2020-08-04 17:06:09 PDT
Comment on attachment 405936 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=405936&action=review

> Tools/Scripts/libraries/webkitcorepy/webkitcorepy/tests/mocks/context_stack_unittest.py:51
> +

Could you tell me more about the use case of this? Can we just use mock.patch context manager to do this?

def foo():
    return 'a

with patch('__main__.foo', new=lambda : 'b'):
    print(foo())
    with patch('__main__.foo', new=lambda : 'c'):
        print(foo())
    print(foo())

I got:
b
c
b
Comment 8 dewei_zhu 2020-08-04 17:07:35 PDT
Comment on attachment 405936 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=405936&action=review

> Tools/Scripts/libraries/webkitcorepy/webkitcorepy/tests/mocks/context_stack_unittest.py:70
> +

Maybe we want to check stack_1 again when we are out of stack_2 context.

> Tools/Scripts/libraries/webkitcorepy/webkitcorepy/tests/mocks/context_stack_unittest.py:79
> +                self.assertEqual(str(stack_2), to_be_replaced())

Ditto here.
Comment 9 Jonathan Bedard 2020-08-04 17:38:27 PDT
Comment on attachment 405936 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=405936&action=review

>> Tools/Scripts/libraries/webkitcorepy/webkitcorepy/tests/mocks/context_stack_unittest.py:51
>> +
> 
> Could you tell me more about the use case of this? Can we just use mock.patch context manager to do this?
> 
> def foo():
>     return 'a
> 
> with patch('__main__.foo', new=lambda : 'b'):
>     print(foo())
>     with patch('__main__.foo', new=lambda : 'c'):
>         print(foo())
>     print(foo())
> 
> I got:
> b
> c
> b

This is what you should get.

This class is useful for mocking out functions which have arguments that need to be conceptually separated. Take, for example, mocking requests. First, to mock requests, we have, if I recall, 7 or 8 calls that need to be mocked in a very similar way, hence the list of patches, but more importantly, a specific logical context would only apply to a single domain. This is basically the case where I want to do this:

requests to https://results.webkit.org -> handler_for_results_database(url)
requests to https://build.webkit.org -> handler_for_build_webkit_org(url)

We could try and do this with a single mock function, but it's likely we already have a handler for each of these, it would be nice if we didn't have to re-build the handler each time, and do something like so:

with MockResultsWebKitOrg():
    with MockBuildWebKitOrg():
        # Stuff to test

And that's where the whole 'top' and 'stack' bit come in. Our generic mocking structure for requests will do something like this:

class RequestsMockStack(ContextStack):
    top = None

    ....

    def route(self, args):
        # Virtual function defined by children classes

    def _route(self, args):
        if meetsCondition(args):
            return self.route(args)
        if self.top:
            return self._route(args)
        raise Exception('Nothing in the stack matched request conditions')

So we can stack a bunch of request handlers together without having to re-declare the shared ones. You can do a similar thing with subprocess and even filesystem primitives.
Comment 10 Jonathan Bedard 2020-08-04 21:13:22 PDT
Comment on attachment 405936 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=405936&action=review

>> Tools/Scripts/libraries/webkitcorepy/webkitcorepy/tests/mocks/context_stack_unittest.py:70
>> +
> 
> Maybe we want to check stack_1 again when we are out of stack_2 context.

Good idea, making the change!
Comment 11 Jonathan Bedard 2020-08-04 21:15:10 PDT
Created attachment 405983 [details]
Patch
Comment 12 EWS 2020-08-04 22:15:34 PDT
Committed r265277: <https://trac.webkit.org/changeset/265277>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 405983 [details].