Bug 214484

Summary: [webkitcorepy] Add mocks.ContextStack
Product: WebKit Reporter: Jonathan Bedard <jbedard>
Component: Tools / TestsAssignee: Jonathan Bedard <jbedard>
Status: RESOLVED FIXED    
Severity: Normal CC: dewei_zhu, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: Safari 13   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=214378
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch none

Jonathan Bedard
Reported 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.
Attachments
Patch (10.64 KB, patch)
2020-07-17 10:30 PDT, Jonathan Bedard
no flags
Patch (11.21 KB, patch)
2020-07-22 12:22 PDT, Jonathan Bedard
no flags
Patch (10.85 KB, patch)
2020-07-30 09:11 PDT, Jonathan Bedard
no flags
Patch (10.87 KB, patch)
2020-07-30 21:11 PDT, Jonathan Bedard
no flags
Patch (10.86 KB, patch)
2020-08-04 12:36 PDT, Jonathan Bedard
no flags
Patch (11.13 KB, patch)
2020-08-04 21:15 PDT, Jonathan Bedard
no flags
Jonathan Bedard
Comment 1 2020-07-17 10:30:35 PDT
Jonathan Bedard
Comment 2 2020-07-22 12:22:08 PDT
Radar WebKit Bug Importer
Comment 3 2020-07-24 10:25:16 PDT
Jonathan Bedard
Comment 4 2020-07-30 09:11:33 PDT
Jonathan Bedard
Comment 5 2020-07-30 21:11:09 PDT
Jonathan Bedard
Comment 6 2020-08-04 12:36:25 PDT
dewei_zhu
Comment 7 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
dewei_zhu
Comment 8 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.
Jonathan Bedard
Comment 9 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.
Jonathan Bedard
Comment 10 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!
Jonathan Bedard
Comment 11 2020-08-04 21:15:10 PDT
EWS
Comment 12 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].
Note You need to log in before you can comment on or make changes to this bug.