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.
Created attachment 404572 [details] Patch
Created attachment 404948 [details] Patch
<rdar://problem/66060898>
Created attachment 405576 [details] Patch
Created attachment 405661 [details] Patch
Created attachment 405936 [details] Patch
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 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 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 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!
Created attachment 405983 [details] Patch
Committed r265277: <https://trac.webkit.org/changeset/265277> All reviewed patches have been landed. Closing bug and clearing flags on attachment 405983 [details].