-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(#33): add support for user defined custom mock engine
- Loading branch information
Showing
5 changed files
with
226 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
from .interceptors import interceptors | ||
|
||
|
||
class MockEngine(object): | ||
""" | ||
MockEngine implements the built-in `pook` mock engine based on HTTP | ||
interceptors strategy. | ||
Mock engines must implementent the following methods: | ||
- `engine.__init__(self, engine)` | ||
- `engine.activate(self)` | ||
- `engine.disable(self)` | ||
Mock engines can optionally implement the follow methods: | ||
- `engine.add_interceptors(self, *interceptors)` | ||
- `engine.flush_interceptors(self)` | ||
- `engine.disable_interceptor(self, name) -> bool` | ||
Arguments: | ||
engine (pook.Engine): injected pook engine to be used. | ||
Attributes: | ||
engine (pook.Engine): stores pook engine to be used. | ||
interceptors (list[pook.BaseInterceptor]): stores engine-level HTTP | ||
traffic interceptors. | ||
""" | ||
|
||
def __init__(self, engine): | ||
# Store pook engine | ||
self.engine = engine | ||
# Store HTTP client interceptors | ||
self.interceptors = [] | ||
# Self-register built-in interceptors | ||
self.add_interceptor(*interceptors) | ||
|
||
def add_interceptor(self, *interceptors): | ||
""" | ||
Adds one or multiple HTTP traffic interceptors to the current | ||
mocking engine. | ||
Interceptors are typically HTTP client specific wrapper classes that | ||
implements the pook interceptor interface. | ||
Arguments: | ||
interceptors (pook.interceptors.BaseInterceptor) | ||
""" | ||
for interceptor in interceptors: | ||
self.interceptors.append(interceptor(self.engine)) | ||
|
||
def flush_interceptors(self): | ||
""" | ||
Flushes registered interceptors in the current mocking engine. | ||
This method is low-level. Only call it if you know what you are doing. | ||
""" | ||
self.interceptors = [] | ||
|
||
def remove_interceptor(self, name): | ||
""" | ||
Removes a specific interceptor by name. | ||
Arguments: | ||
name (str): interceptor name to disable. | ||
Returns: | ||
bool: `True` if the interceptor was disabled, otherwise `False`. | ||
""" | ||
for index, interceptor in enumerate(self.interceptors): | ||
matches = ( | ||
type(interceptor).__name__ == name or | ||
getattr(interceptor, 'name') == name | ||
) | ||
if matches: | ||
self.interceptors.pop(index) | ||
return True | ||
return False | ||
|
||
def activate(self): | ||
""" | ||
Activates the registered interceptors in the mocking engine. | ||
This means any HTTP traffic captures by those interceptors will | ||
trigger the HTTP mock matching engine in order to determine if a given | ||
HTTP transaction should be mocked out or not. | ||
""" | ||
[interceptor.activate() for interceptor in self.interceptors] | ||
|
||
def disable(self): | ||
""" | ||
Disables interceptors and stops intercepting any outgoing HTTP traffic. | ||
""" | ||
# Restore HTTP interceptors | ||
for interceptor in self.interceptors: | ||
try: | ||
interceptor.disable() | ||
except RuntimeError: | ||
pass # explicitely ignore runtime patch errors |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
import pytest | ||
from pook import MockEngine, Engine | ||
from pook.interceptors import BaseInterceptor | ||
|
||
|
||
class Interceptor(BaseInterceptor): | ||
def activate(self): | ||
self.active = True | ||
|
||
def disable(self): | ||
self.active = False | ||
|
||
|
||
@pytest.fixture | ||
def engine(): | ||
return MockEngine(Engine()) | ||
|
||
|
||
def test_mock_engine_instance(engine): | ||
assert isinstance(engine.engine, Engine) | ||
assert isinstance(engine.interceptors, list) | ||
assert len(engine.interceptors) >= 2 | ||
|
||
|
||
def test_mock_engine_flush(engine): | ||
assert len(engine.interceptors) == 2 | ||
engine.flush_interceptors() | ||
assert len(engine.interceptors) == 0 | ||
|
||
|
||
def test_mock_engine_interceptors(engine): | ||
engine.flush_interceptors() | ||
engine.add_interceptor(Interceptor) | ||
assert len(engine.interceptors) == 1 | ||
assert isinstance(engine.interceptors[0], Interceptor) | ||
|
||
engine.remove_interceptor('Interceptor') | ||
assert len(engine.interceptors) == 0 | ||
|
||
|
||
def test_mock_engine_status(engine): | ||
engine.flush_interceptors() | ||
engine.add_interceptor(Interceptor) | ||
assert len(engine.interceptors) == 1 | ||
|
||
interceptor = engine.interceptors[0] | ||
engine.activate() | ||
assert interceptor.active | ||
|
||
engine.disable() | ||
assert not interceptor.active |
1ea3796
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job! I'll have a look at it soon. 👍