stoobly-agent 0.21.2__py3-none-any.whl → 0.22.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- stoobly_agent/__init__.py +2 -1
- stoobly_agent/app/api/bodies_controller.py +2 -2
- stoobly_agent/app/api/requests_controller.py +28 -10
- stoobly_agent/app/api/simple_http_request_handler.py +1 -1
- stoobly_agent/app/cli/ca_cert_installer.py +16 -5
- stoobly_agent/app/cli/config_cli.py +32 -20
- stoobly_agent/app/cli/helpers/context.py +7 -0
- stoobly_agent/app/cli/helpers/handle_mock_service.py +14 -0
- stoobly_agent/app/cli/helpers/print_service.py +1 -1
- stoobly_agent/app/cli/intercept.py +46 -2
- stoobly_agent/app/cli/main_group.py +3 -3
- stoobly_agent/app/cli/project_cli.py +3 -1
- stoobly_agent/app/cli/request_cli.py +6 -10
- stoobly_agent/app/models/adapters/mitmproxy/__init__.py +2 -0
- stoobly_agent/app/models/adapters/mitmproxy/request/__init__.py +12 -0
- stoobly_agent/app/models/adapters/mitmproxy/request/python_adapter.py +16 -0
- stoobly_agent/app/models/adapters/mitmproxy/response/__init__.py +12 -0
- stoobly_agent/app/models/adapters/mitmproxy/response/python_adapter.py +24 -0
- stoobly_agent/app/models/adapters/python/__init__.py +2 -0
- stoobly_agent/app/models/adapters/python/request/__init__.py +18 -0
- stoobly_agent/app/models/adapters/python/request/mitmproxy_adapter.py +53 -0
- stoobly_agent/app/models/adapters/python/request/stoobly_adapter.py +49 -0
- stoobly_agent/app/models/adapters/python/response/__init__.py +13 -0
- stoobly_agent/app/models/adapters/{mitmproxy_response_adapter.py → python/response/mitmproxy_adapter.py} +15 -7
- stoobly_agent/app/models/adapters/raw_http_response_adapter.py +10 -3
- stoobly_agent/app/models/adapters/stoobly/request/__init__.py +11 -0
- stoobly_agent/app/models/adapters/stoobly/request/mitmproxy_adapter.py +32 -0
- stoobly_agent/app/models/body_model.py +2 -2
- stoobly_agent/app/models/factories/__init__.py +0 -0
- stoobly_agent/app/models/factories/resource/__init__.py +0 -0
- stoobly_agent/app/models/{adapters/body_adapter_factory.py → factories/resource/body.py} +1 -1
- stoobly_agent/app/models/{adapters/header_adapter_factory.py → factories/resource/header.py} +1 -1
- stoobly_agent/app/models/factories/resource/local_db/__init__.py +0 -0
- stoobly_agent/app/models/{adapters → factories/resource}/local_db/replayed_response_adapter.py +1 -2
- stoobly_agent/app/models/{adapters → factories/resource}/local_db/request_adapter.py +15 -8
- stoobly_agent/app/models/{adapters → factories/resource}/local_db/scenario_adapter.py +13 -7
- stoobly_agent/app/models/{adapters/query_param_adapter_factory.py → factories/resource/query_param.py} +1 -1
- stoobly_agent/app/models/{adapters/replayed_response_adapter_factory.py → factories/resource/replayed_response.py} +1 -1
- stoobly_agent/app/models/{adapters/request_adapter_factory.py → factories/resource/request.py} +2 -2
- stoobly_agent/app/models/{adapters/response_adapter_factory.py → factories/resource/response.py} +1 -1
- stoobly_agent/app/models/{adapters/response_header_adapter_factory.py → factories/resource/response_header.py} +1 -1
- stoobly_agent/app/models/{adapters/scenario_adapter_factory.py → factories/resource/scenario.py} +2 -2
- stoobly_agent/app/models/factories/resource/stoobly/__init__.py +0 -0
- stoobly_agent/app/models/{adapters/stoobly_request_adapter.py → factories/resource/stoobly/request_adapter.py} +1 -2
- stoobly_agent/app/models/{adapters/stoobly_scenario_adapter.py → factories/resource/stoobly/scenario_adapter.py} +1 -2
- stoobly_agent/app/models/header_model.py +2 -2
- stoobly_agent/app/models/query_param_model.py +2 -2
- stoobly_agent/app/models/replayed_response_model.py +2 -2
- stoobly_agent/app/models/request_model.py +4 -5
- stoobly_agent/app/models/response_header_model.py +2 -2
- stoobly_agent/app/models/response_model.py +2 -2
- stoobly_agent/app/models/scenario_model.py +4 -4
- stoobly_agent/app/models/schemas/request.py +8 -1
- stoobly_agent/app/models/types/__init__.py +6 -0
- stoobly_agent/app/proxy/__init__.py +0 -5
- stoobly_agent/app/proxy/handle_mock_service.py +0 -3
- stoobly_agent/app/proxy/handle_test_service.py +1 -1
- stoobly_agent/app/proxy/intercept_handler.py +0 -1
- stoobly_agent/app/proxy/mitmproxy/flow_mock.py +35 -0
- stoobly_agent/app/proxy/mitmproxy/request_facade.py +11 -2
- stoobly_agent/app/proxy/replay/replay_request_service.py +57 -40
- stoobly_agent/app/proxy/simulate_intercept_service.py +30 -0
- stoobly_agent/app/proxy/test/__init__.py +1 -0
- stoobly_agent/app/proxy/test/context.py +2 -1
- stoobly_agent/app/proxy/test/context_abc.py +155 -0
- stoobly_agent/app/proxy/test/matchers/context.py +1 -1
- stoobly_agent/app/proxy/test/matchers/contract.py +1 -1
- stoobly_agent/app/proxy/test/matchers/custom.py +1 -1
- stoobly_agent/app/proxy/test/matchers/diff.py +1 -1
- stoobly_agent/app/proxy/test/matchers/fuzzy.py +1 -1
- stoobly_agent/app/proxy/test/test_service.py +1 -1
- stoobly_agent/app/proxy/upload/joined_request.py +0 -1
- stoobly_agent/app/proxy/upload/proxy_request.py +4 -1
- stoobly_agent/app/proxy/upload/request_string.py +1 -1
- stoobly_agent/app/settings/constants/mode.py +3 -0
- stoobly_agent/cli.py +76 -7
- stoobly_agent/config/constants/env_vars.py +2 -1
- stoobly_agent/config/data_dir.py +11 -8
- stoobly_agent/lib/api/api.py +4 -4
- stoobly_agent/lib/api/keys/organization_key.py +2 -0
- stoobly_agent/lib/api/keys/project_key.py +9 -0
- stoobly_agent/lib/api/scenarios_resource.py +1 -1
- stoobly_agent/lib/api/stoobly_api.py +9 -5
- stoobly_agent/lib/orm/__init__.py +1 -1
- stoobly_agent/lib/orm/replayed_response.py +3 -3
- stoobly_agent/lib/orm/request.py +25 -5
- stoobly_agent/lib/orm/transformers/orm_to_stoobly_request_transformer.py +1 -1
- stoobly_agent/mock.py +94 -0
- stoobly_agent/public/{2-es2015.3d54569af612a07a2e06.js → 1-es2015.37917aa26708d8f35d36.js} +1 -1
- stoobly_agent/public/{2-es5.3d54569af612a07a2e06.js → 1-es5.37917aa26708d8f35d36.js} +1 -1
- stoobly_agent/public/10-es2015.e9556b0d0f0e92fb548b.js +1 -0
- stoobly_agent/public/10-es5.e9556b0d0f0e92fb548b.js +1 -0
- stoobly_agent/public/11-es2015.bc6212fccbe72a623f81.js +1 -0
- stoobly_agent/public/11-es5.bc6212fccbe72a623f81.js +1 -0
- stoobly_agent/public/{13-es2015.76b6c147b0c46f995cd7.js → 12-es2015.d0768894ddffd6efa5e5.js} +1 -1
- stoobly_agent/public/{13-es5.76b6c147b0c46f995cd7.js → 12-es5.d0768894ddffd6efa5e5.js} +1 -1
- stoobly_agent/public/13-es2015.8a044490a76fd298162d.js +1 -0
- stoobly_agent/public/13-es5.8a044490a76fd298162d.js +1 -0
- stoobly_agent/public/{15-es2015.60c3b41c385f5bdedb7b.js → 14-es2015.1cd1a021e51ca0e62e1c.js} +1 -1
- stoobly_agent/public/{15-es5.60c3b41c385f5bdedb7b.js → 14-es5.1cd1a021e51ca0e62e1c.js} +1 -1
- stoobly_agent/public/{16-es2015.5d395009a77978db4405.js → 15-es2015.587781d19864ff0eb4f5.js} +1 -1
- stoobly_agent/public/{16-es5.5d395009a77978db4405.js → 15-es5.587781d19864ff0eb4f5.js} +1 -1
- stoobly_agent/public/16-es2015.ec6a175b1f9578203cd8.js +1 -0
- stoobly_agent/public/16-es5.ec6a175b1f9578203cd8.js +1 -0
- stoobly_agent/public/17-es2015.ad9c4756c96a15bd29d7.js +1 -0
- stoobly_agent/public/17-es5.ad9c4756c96a15bd29d7.js +1 -0
- stoobly_agent/public/{19-es2015.517f68e08f4c582dae66.js → 18-es2015.8583df0f8eccb3e47c0b.js} +1 -1
- stoobly_agent/public/{19-es5.517f68e08f4c582dae66.js → 18-es5.8583df0f8eccb3e47c0b.js} +1 -1
- stoobly_agent/public/{20-es2015.473486aabfa4d4a6431b.js → 19-es2015.d0225852a844dc03a09f.js} +1 -1
- stoobly_agent/public/{20-es5.473486aabfa4d4a6431b.js → 19-es5.d0225852a844dc03a09f.js} +1 -1
- stoobly_agent/public/{3-es5.1dad290844ea619e4c16.js → 2-es2015.8f184ac63348ba447b1f.js} +1 -1
- stoobly_agent/public/{3-es2015.1dad290844ea619e4c16.js → 2-es5.8f184ac63348ba447b1f.js} +1 -1
- stoobly_agent/public/{21-es2015.56aa10803cc1348a55a3.js → 20-es2015.f7c107847935264d58aa.js} +1 -1
- stoobly_agent/public/{21-es5.56aa10803cc1348a55a3.js → 20-es5.f7c107847935264d58aa.js} +1 -1
- stoobly_agent/public/{22-es2015.46d81010003b2a50eeab.js → 21-es2015.dd358e1edaf3d32dd2c0.js} +1 -1
- stoobly_agent/public/{22-es5.46d81010003b2a50eeab.js → 21-es5.dd358e1edaf3d32dd2c0.js} +1 -1
- stoobly_agent/public/26-es2015.6332c32f1b7c8c288f2f.js +1 -0
- stoobly_agent/public/26-es5.6332c32f1b7c8c288f2f.js +1 -0
- stoobly_agent/public/27-es2015.af505e744b0c869a93d1.js +1 -0
- stoobly_agent/public/27-es5.af505e744b0c869a93d1.js +1 -0
- stoobly_agent/public/28-es2015.7c7c0f64e4af29d2e4d4.js +1 -0
- stoobly_agent/public/28-es5.7c7c0f64e4af29d2e4d4.js +1 -0
- stoobly_agent/public/32-es2015.2ab8267be7275dee9059.js +1 -0
- stoobly_agent/public/32-es5.2ab8267be7275dee9059.js +1 -0
- stoobly_agent/public/{34-es2015.ef24f6f7630620a38b19.js → 33-es2015.5b575f3a87c6c2c6b93b.js} +1 -1
- stoobly_agent/public/{34-es5.ef24f6f7630620a38b19.js → 33-es5.5b575f3a87c6c2c6b93b.js} +1 -1
- stoobly_agent/public/{35-es2015.0667e742725cc828f59f.js → 34-es2015.6a1160649c718cdb9338.js} +1 -1
- stoobly_agent/public/{35-es5.0667e742725cc828f59f.js → 34-es5.6a1160649c718cdb9338.js} +1 -1
- stoobly_agent/public/35-es2015.1b9dc7a46a6d5296c3ae.js +1 -0
- stoobly_agent/public/35-es5.1b9dc7a46a6d5296c3ae.js +1 -0
- stoobly_agent/public/{37-es2015.50d0c2d3fe4d0a74fc8f.js → 36-es2015.2fc9151fe6a5ff2bff31.js} +1 -1
- stoobly_agent/public/{37-es5.50d0c2d3fe4d0a74fc8f.js → 36-es5.2fc9151fe6a5ff2bff31.js} +1 -1
- stoobly_agent/public/{38-es2015.c14bde0b8d0cc14e915e.js → 37-es2015.ac7108c3625fd6e1d981.js} +1 -1
- stoobly_agent/public/{38-es5.c14bde0b8d0cc14e915e.js → 37-es5.ac7108c3625fd6e1d981.js} +1 -1
- stoobly_agent/public/38-es2015.9c183b14373c0e449932.js +1 -0
- stoobly_agent/public/38-es5.9c183b14373c0e449932.js +1 -0
- stoobly_agent/public/39-es2015.4624cdeb29fe9850b216.js +1 -0
- stoobly_agent/public/39-es5.4624cdeb29fe9850b216.js +1 -0
- stoobly_agent/public/40-es2015.24d981230c0c8f369cde.js +1 -0
- stoobly_agent/public/40-es5.24d981230c0c8f369cde.js +1 -0
- stoobly_agent/public/{46-es2015.abc7e4fd207d54277fcb.js → 45-es2015.c76937ed45d460bcd36f.js} +1 -1
- stoobly_agent/public/{46-es5.abc7e4fd207d54277fcb.js → 45-es5.c76937ed45d460bcd36f.js} +1 -1
- stoobly_agent/public/6-es2015.53acc5d2ca7f48ef857f.js +1 -0
- stoobly_agent/public/6-es5.53acc5d2ca7f48ef857f.js +1 -0
- stoobly_agent/public/7-es2015.1c6b3d315d50ccd228cb.js +1 -0
- stoobly_agent/public/7-es5.1c6b3d315d50ccd228cb.js +1 -0
- stoobly_agent/public/{9-es2015.ef0f7cb32f5fadb085d0.js → 8-es2015.0fe7492f7b61eb4699b6.js} +1 -1
- stoobly_agent/public/{9-es5.ef0f7cb32f5fadb085d0.js → 8-es5.0fe7492f7b61eb4699b6.js} +1 -1
- stoobly_agent/public/common-es2015.86f70de6df2c705a87f6.js +1 -0
- stoobly_agent/public/common-es5.86f70de6df2c705a87f6.js +1 -0
- stoobly_agent/public/dashboard.agent-alpha-0.22.3.tar.gz +0 -0
- stoobly_agent/public/index.html +1 -1
- stoobly_agent/public/main-es2015.aceb967cb4cccc0bc521.js +1 -0
- stoobly_agent/public/main-es5.aceb967cb4cccc0bc521.js +1 -0
- stoobly_agent/public/{polyfills-es2015.2b40b2ecdf98a9210572.js → polyfills-es2015.580f7a6e775c2c348c9d.js} +1 -1
- stoobly_agent/public/{polyfills-es5.d9fb2eee68607c3f7f64.js → polyfills-es5.4c3461a071d35be3dd81.js} +1 -1
- stoobly_agent/public/runtime-es2015.49eaebd2913fa7fe2b97.js +1 -0
- stoobly_agent/public/runtime-es5.49eaebd2913fa7fe2b97.js +1 -0
- stoobly_agent/test/test_helper.py +4 -5
- {stoobly_agent-0.21.2.dist-info → stoobly_agent-0.22.3.dist-info}/METADATA +1 -1
- {stoobly_agent-0.21.2.dist-info → stoobly_agent-0.22.3.dist-info}/RECORD +175 -157
- {stoobly_agent-0.21.2.dist-info → stoobly_agent-0.22.3.dist-info}/WHEEL +1 -1
- stoobly_agent/app/models/adapters/mitmproxy_request_adapter.py +0 -60
- stoobly_agent/app/models/adapters/types/__init__.py +0 -3
- stoobly_agent/public/11-es2015.b85bdc528bab0ee542fe.js +0 -1
- stoobly_agent/public/11-es5.b85bdc528bab0ee542fe.js +0 -1
- stoobly_agent/public/12-es2015.72399d40488de533bb97.js +0 -1
- stoobly_agent/public/12-es5.72399d40488de533bb97.js +0 -1
- stoobly_agent/public/14-es2015.7cedfd0829bd7a64677a.js +0 -1
- stoobly_agent/public/14-es5.7cedfd0829bd7a64677a.js +0 -1
- stoobly_agent/public/17-es2015.f6f28ba9f681063632a8.js +0 -1
- stoobly_agent/public/17-es5.f6f28ba9f681063632a8.js +0 -1
- stoobly_agent/public/18-es2015.b0cd6822ebd1090b0d60.js +0 -1
- stoobly_agent/public/18-es5.b0cd6822ebd1090b0d60.js +0 -1
- stoobly_agent/public/27-es2015.4635450ff709f7868796.js +0 -1
- stoobly_agent/public/27-es5.4635450ff709f7868796.js +0 -1
- stoobly_agent/public/28-es2015.1b29b35529772ab108f1.js +0 -1
- stoobly_agent/public/28-es5.1b29b35529772ab108f1.js +0 -1
- stoobly_agent/public/32-es2015.862b67803e6242451976.js +0 -1
- stoobly_agent/public/32-es5.862b67803e6242451976.js +0 -1
- stoobly_agent/public/33-es2015.4ff4325d1aec37e1b43c.js +0 -1
- stoobly_agent/public/33-es5.4ff4325d1aec37e1b43c.js +0 -1
- stoobly_agent/public/36-es2015.cd370fdf8990019d0c8e.js +0 -1
- stoobly_agent/public/36-es5.cd370fdf8990019d0c8e.js +0 -1
- stoobly_agent/public/39-es2015.4ec5fc16202c4759eac4.js +0 -1
- stoobly_agent/public/39-es5.4ec5fc16202c4759eac4.js +0 -1
- stoobly_agent/public/40-es2015.25287ce77b40050f3471.js +0 -1
- stoobly_agent/public/40-es5.25287ce77b40050f3471.js +0 -1
- stoobly_agent/public/45-es2015.fd110741ac0fbaada177.js +0 -1
- stoobly_agent/public/45-es5.fd110741ac0fbaada177.js +0 -1
- stoobly_agent/public/6-es2015.7219d596e3545ebaed3a.js +0 -1
- stoobly_agent/public/6-es5.7219d596e3545ebaed3a.js +0 -1
- stoobly_agent/public/7-es2015.98b085349ebd9d246060.js +0 -1
- stoobly_agent/public/7-es5.98b085349ebd9d246060.js +0 -1
- stoobly_agent/public/8-es2015.335fd5c122ad083aec65.js +0 -1
- stoobly_agent/public/8-es5.335fd5c122ad083aec65.js +0 -1
- stoobly_agent/public/common-es2015.81f870bf87411a04446d.js +0 -1
- stoobly_agent/public/common-es5.81f870bf87411a04446d.js +0 -1
- stoobly_agent/public/dashboard.agent-alpha-0.21.0.tar.gz +0 -0
- stoobly_agent/public/main-es2015.575c1d17fc866d3a6649.js +0 -1
- stoobly_agent/public/main-es5.575c1d17fc866d3a6649.js +0 -1
- stoobly_agent/public/runtime-es2015.8915d042dc9b55368999.js +0 -1
- stoobly_agent/public/runtime-es5.8915d042dc9b55368999.js +0 -1
- /stoobly_agent/app/models/adapters/{local_db → stoobly}/__init__.py +0 -0
- /stoobly_agent/app/models/{adapters → factories/resource}/local_db/body_adapter.py +0 -0
- /stoobly_agent/app/models/{adapters → factories/resource}/local_db/header_adapter.py +0 -0
- /stoobly_agent/app/models/{adapters → factories/resource}/local_db/query_param_adapter.py +0 -0
- /stoobly_agent/app/models/{adapters → factories/resource}/local_db/response_adapter.py +0 -0
- /stoobly_agent/app/models/{adapters → factories/resource}/local_db/response_header_adapter.py +0 -0
- /stoobly_agent/app/models/{adapters/types → types}/replayed_response.py +0 -0
- /stoobly_agent/app/models/{adapters/types → types}/request_create_params.py +0 -0
- /stoobly_agent/app/models/{adapters/types → types}/request_show_params.py +0 -0
- /stoobly_agent/app/models/{adapters/types → types}/scenario_create_params.py +0 -0
- {stoobly_agent-0.21.2.dist-info → stoobly_agent-0.22.3.dist-info}/LICENSE +0 -0
- {stoobly_agent-0.21.2.dist-info → stoobly_agent-0.22.3.dist-info}/entry_points.txt +0 -0
- {stoobly_agent-0.21.2.dist-info → stoobly_agent-0.22.3.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,21 @@
|
|
1
|
-
|
1
|
+
import pdb
|
2
2
|
import requests
|
3
3
|
|
4
4
|
from mitmproxy.http import Headers, Response as MitmproxyResponse
|
5
|
+
from time import time
|
6
|
+
|
7
|
+
from stoobly_agent.app.models.adapters.raw_http_request_adapter import DEFAULT_HTTP_VERSION
|
5
8
|
|
6
9
|
class MitmproxyResponseAdapter():
|
7
10
|
|
8
|
-
def __init__(self,
|
11
|
+
def __init__(self, response: requests.Response):
|
9
12
|
self.__timestamp_start = time()
|
10
|
-
|
13
|
+
|
14
|
+
if hasattr(response, 'raw'):
|
15
|
+
self.__http_version = f"HTTP/{response.raw.version / 10.0}"
|
16
|
+
else:
|
17
|
+
self.__http_version = DEFAULT_HTTP_VERSION
|
18
|
+
|
11
19
|
self.__latency = 0 # Seconds
|
12
20
|
self.__response = response
|
13
21
|
|
@@ -41,11 +49,11 @@ class MitmproxyResponseAdapter():
|
|
41
49
|
|
42
50
|
def adapt(self):
|
43
51
|
body = b''
|
44
|
-
|
45
|
-
|
46
|
-
body = self.__response.raw.data
|
47
|
-
except:
|
52
|
+
|
53
|
+
if self.__response._content_consumed or not hasattr(self.__response, 'raw'):
|
48
54
|
body = self.__response.content
|
55
|
+
else:
|
56
|
+
body = self.__response.raw.data
|
49
57
|
|
50
58
|
return MitmproxyResponse(
|
51
59
|
self.__http_version,
|
@@ -6,6 +6,7 @@ from io import BytesIO
|
|
6
6
|
from mitmproxy.net import encoding
|
7
7
|
from requests.structures import CaseInsensitiveDict
|
8
8
|
from typing import Union
|
9
|
+
from urllib3 import HTTPResponse
|
9
10
|
|
10
11
|
from stoobly_agent.app.proxy.mitmproxy.response import Response
|
11
12
|
from stoobly_agent.lib.orm.utils.response_parse_handler import Response as ResponseDict, ResponseParseHandler
|
@@ -39,8 +40,14 @@ class RawHttpResponseAdapter():
|
|
39
40
|
response.status_code = self.status
|
40
41
|
response.headers = self.headers
|
41
42
|
|
42
|
-
|
43
|
-
|
43
|
+
response.raw = HTTPResponse(
|
44
|
+
body=BytesIO(self.body),
|
45
|
+
decode_content=False,
|
46
|
+
headers=self.headers,
|
47
|
+
preload_content=False
|
48
|
+
)
|
49
|
+
|
50
|
+
#response.raw = self.__decode_body(self.body, content_encoding)
|
44
51
|
|
45
52
|
return response
|
46
53
|
|
@@ -70,7 +77,7 @@ class RawHttpResponseAdapter():
|
|
70
77
|
def __parse_response_line(self, response_line):
|
71
78
|
response_parts = response_line.split(b' ')
|
72
79
|
self.protocol = self.__decode(response_parts[0]) if len(response_parts) > 2 else DEFAULT_HTTP_VERSION
|
73
|
-
self.status = self.__decode(response_parts[1])
|
80
|
+
self.status = int(self.__decode(response_parts[1]))
|
74
81
|
self.reason = self.__decode(response_parts[2]) if len(response_parts) > 2 else ''
|
75
82
|
|
76
83
|
def __str__(self):
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from lib.api.interfaces.requests import RequestShowResponse
|
2
|
+
|
3
|
+
from .mitmproxy_adapter import MitmproxyRequestAdapter
|
4
|
+
|
5
|
+
class StooblyRequestAdapterFactory():
|
6
|
+
|
7
|
+
def __init__(self, request: RequestShowResponse):
|
8
|
+
self.__request = request
|
9
|
+
|
10
|
+
def mitmproxy_request(self):
|
11
|
+
return MitmproxyRequestAdapter(self.__request)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import pdb
|
2
|
+
import requests
|
3
|
+
|
4
|
+
from mitmproxy.http import Headers, Request as MitmproxyRequest
|
5
|
+
|
6
|
+
from stoobly_agent.app.models.schemas.request import Request
|
7
|
+
|
8
|
+
class MitmproxyRequestAdapter():
|
9
|
+
|
10
|
+
def __init__(self, request: Request):
|
11
|
+
self.__http_version = 'HTTP/1.1'
|
12
|
+
self.__request = request
|
13
|
+
|
14
|
+
@property
|
15
|
+
def headers(self):
|
16
|
+
return Headers(**self.__decode_dict(self.__request.headers))
|
17
|
+
|
18
|
+
def adapt(self):
|
19
|
+
request = MitmproxyRequest.make(
|
20
|
+
self.__request.method,
|
21
|
+
self.__request.url,
|
22
|
+
self.__request.body,
|
23
|
+
self.headers,
|
24
|
+
)
|
25
|
+
request.http_version = self.__http_version
|
26
|
+
return request
|
27
|
+
|
28
|
+
def __decode_dict(self, d):
|
29
|
+
new_d = {}
|
30
|
+
for k, v in d.items():
|
31
|
+
new_d[k.decode() if isinstance(k, bytes) else k] = v.decode() if isinstance(v, bytes) else v
|
32
|
+
return new_d
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import pdb
|
2
2
|
import requests
|
3
3
|
|
4
|
-
from stoobly_agent.app.models.adapters.body_adapter_factory import BodyAdapterFactory
|
5
4
|
from stoobly_agent.app.settings import Settings
|
6
5
|
from stoobly_agent.lib.logger import Logger
|
7
6
|
|
7
|
+
from .factories.resource.body import BodyResourceFactory
|
8
8
|
from .model import Model
|
9
9
|
|
10
10
|
class BodyModel(Model):
|
@@ -13,7 +13,7 @@ class BodyModel(Model):
|
|
13
13
|
super().__init__(settings)
|
14
14
|
|
15
15
|
def as_local(self):
|
16
|
-
self.adapter =
|
16
|
+
self.adapter = BodyResourceFactory(self.settings.remote).local_db()
|
17
17
|
|
18
18
|
def as_remote(self):
|
19
19
|
# 'Not yet supported.'
|
File without changes
|
File without changes
|
File without changes
|
stoobly_agent/app/models/{adapters → factories/resource}/local_db/replayed_response_adapter.py
RENAMED
@@ -1,14 +1,13 @@
|
|
1
1
|
import pdb
|
2
2
|
import requests
|
3
3
|
|
4
|
+
from stoobly_agent.app.models.types import ReplayedResponseIndexQueryParams
|
4
5
|
from stoobly_agent.lib.api.interfaces.requests import RequestShowResponse
|
5
6
|
from stoobly_agent.lib.orm.replayed_response import ReplayedResponse
|
6
7
|
from stoobly_agent.lib.orm.transformers.orm_to_requests_response_transformer import ORMToRequestsResponseTransformer
|
7
8
|
from stoobly_agent.lib.orm.transformers.orm_to_stoobly_request_transformer import ORMToStooblyRequestTransformer
|
8
9
|
from stoobly_agent.lib.orm.utils.response_parse_handler import Response
|
9
10
|
|
10
|
-
from ..types.replayed_response import ReplayedResponseIndexQueryParams
|
11
|
-
|
12
11
|
class LocalDBReplayedResponseAdapter():
|
13
12
|
__replayed_response_orm = None
|
14
13
|
|
@@ -3,13 +3,12 @@ from urllib.parse import urlparse
|
|
3
3
|
import requests
|
4
4
|
|
5
5
|
from mitmproxy.http import HTTPFlow as MitmproxyHTTPFlow, Request as MitmproxyRequest
|
6
|
-
from typing import List
|
7
6
|
|
7
|
+
from stoobly_agent.app.models.types import RequestCreateParams, RequestShowParams
|
8
8
|
from stoobly_agent.app.proxy.mock.custom_not_found_response_builder import CustomNotFoundResponseBuilder
|
9
9
|
from stoobly_agent.app.proxy.mock.hashed_request_decorator import HashedRequestDecorator
|
10
10
|
from stoobly_agent.app.proxy.mitmproxy.request_facade import MitmproxyRequestFacade
|
11
11
|
from stoobly_agent.app.proxy.upload.joined_request import JoinedRequest
|
12
|
-
|
13
12
|
from stoobly_agent.lib.orm import ORM
|
14
13
|
from stoobly_agent.lib.orm.request import Request
|
15
14
|
from stoobly_agent.lib.orm.response import Response
|
@@ -19,8 +18,6 @@ from stoobly_agent.lib.orm.types.response_columns import ResponseColumns
|
|
19
18
|
from stoobly_agent.lib.orm.transformers import ORMToRequestsResponseTransformer, ORMToStooblyResponseTransformer
|
20
19
|
from stoobly_agent.lib.api.interfaces import RequestsIndexQueryParams, RequestsIndexResponse, RequestShowResponse
|
21
20
|
|
22
|
-
from ..types import RequestCreateParams, RequestShowParams
|
23
|
-
|
24
21
|
class LocalDBRequestAdapter():
|
25
22
|
__request_orm = None
|
26
23
|
__response_orm = None
|
@@ -73,14 +70,23 @@ class LocalDBRequestAdapter():
|
|
73
70
|
def show(self, request_id: str, **options: RequestShowParams) -> RequestShowResponse:
|
74
71
|
request = self.__request_orm.find(request_id)
|
75
72
|
|
73
|
+
if not request:
|
74
|
+
return CustomNotFoundResponseBuilder().build()
|
75
|
+
|
76
76
|
return ORMToStooblyRequestTransformer(request, options).transform()
|
77
77
|
|
78
78
|
def response(self, **query_params: RequestColumns) -> requests.Response:
|
79
|
-
|
80
|
-
|
79
|
+
request = None
|
80
|
+
|
81
|
+
if not query_params.get('request_id'):
|
82
|
+
request_columns = { **query_params }
|
81
83
|
|
82
|
-
|
83
|
-
|
84
|
+
self.__filter_request_response_columns(request_columns)
|
85
|
+
|
86
|
+
# Find most recent matching record
|
87
|
+
request = self.__request_orm.where_for(**request_columns).get().last()
|
88
|
+
else:
|
89
|
+
request = self.__request_orm.find(query_params.get('request_id'))
|
84
90
|
|
85
91
|
if not request:
|
86
92
|
return CustomNotFoundResponseBuilder().build()
|
@@ -107,6 +113,7 @@ class LocalDBRequestAdapter():
|
|
107
113
|
|
108
114
|
if scenario_id:
|
109
115
|
requests = requests.where('scenario_id', int(scenario_id))
|
116
|
+
sort_order = query_params.get('sort_order') or 'asc'
|
110
117
|
|
111
118
|
if starred:
|
112
119
|
requests = requests.where('starred', starred)
|
@@ -1,13 +1,11 @@
|
|
1
1
|
import pdb
|
2
2
|
|
3
|
-
from stoobly_agent.app.models.
|
3
|
+
from stoobly_agent.app.models.types import ScenarioCreateParams
|
4
4
|
from stoobly_agent.lib.api.interfaces import ScenariosIndexQueryParams, ScenariosIndexResponse, ScenarioShowResponse
|
5
5
|
from stoobly_agent.lib.api.keys.scenario_key import ScenarioKey
|
6
6
|
from stoobly_agent.lib.orm import ORM
|
7
7
|
from stoobly_agent.lib.orm.scenario import Scenario
|
8
8
|
|
9
|
-
from ..types import ScenarioCreateParams
|
10
|
-
|
11
9
|
class LocalDBScenarioAdapter():
|
12
10
|
__scenario_orm = None
|
13
11
|
|
@@ -30,13 +28,21 @@ class LocalDBScenarioAdapter():
|
|
30
28
|
sort_by = query_params.get('sort_by') or 'id'
|
31
29
|
sort_order = query_params.get('sort_order') or 'desc'
|
32
30
|
|
33
|
-
|
34
|
-
|
31
|
+
filter = query_params.get('filter')
|
32
|
+
is_deleted = filter == 'is_deleted'
|
35
33
|
|
36
34
|
scenarios = Scenario.where('is_deleted', is_deleted)
|
37
35
|
|
38
|
-
if starred:
|
39
|
-
scenarios = scenarios.where('starred',
|
36
|
+
if filter == 'starred':
|
37
|
+
scenarios = scenarios.where('starred', True)
|
38
|
+
elif filter == 'high_priority':
|
39
|
+
scenarios = scenarios.where('priority', 3)
|
40
|
+
elif filter == 'medium_priority':
|
41
|
+
scenarios = scenarios.where('priority', 2)
|
42
|
+
elif filter == 'low_priority':
|
43
|
+
scenarios = scenarios.where('priority', 1)
|
44
|
+
elif filter == 'none_priority':
|
45
|
+
scenarios = scenarios.where('priority', 0)
|
40
46
|
|
41
47
|
if query:
|
42
48
|
scenarios = self.__search(scenarios, query)
|
@@ -3,7 +3,7 @@ from stoobly_agent.lib.orm.request import Request
|
|
3
3
|
|
4
4
|
from .local_db.query_param_adapter import LocalDBQueryParamAdapter
|
5
5
|
|
6
|
-
class
|
6
|
+
class QueryParamResourceFactory():
|
7
7
|
|
8
8
|
def __init__(self, settings: RemoteSettings):
|
9
9
|
self.__remote_settings = settings
|
@@ -3,7 +3,7 @@ from stoobly_agent.lib.orm.replayed_response import ReplayedResponse
|
|
3
3
|
|
4
4
|
from .local_db.replayed_response_adapter import LocalDBReplayedResponseAdapter
|
5
5
|
|
6
|
-
class
|
6
|
+
class ReplayedResponseResourceFactory():
|
7
7
|
|
8
8
|
def __init__(self, settings: RemoteSettings):
|
9
9
|
self.__remote_settings = settings
|
stoobly_agent/app/models/{adapters/request_adapter_factory.py → factories/resource/request.py}
RENAMED
@@ -3,9 +3,9 @@ from stoobly_agent.lib.api.requests_resource import RequestsResource
|
|
3
3
|
from stoobly_agent.app.settings import RemoteSettings
|
4
4
|
|
5
5
|
from .local_db.request_adapter import LocalDBRequestAdapter
|
6
|
-
from .
|
6
|
+
from .stoobly.request_adapter import StooblyRequestAdapter
|
7
7
|
|
8
|
-
class
|
8
|
+
class RequestResourceFactory():
|
9
9
|
|
10
10
|
def __init__(self, settings: RemoteSettings):
|
11
11
|
self.__remote_settings = settings
|
stoobly_agent/app/models/{adapters/response_adapter_factory.py → factories/resource/response.py}
RENAMED
@@ -3,7 +3,7 @@ from stoobly_agent.lib.orm.request import Request
|
|
3
3
|
|
4
4
|
from .local_db.response_adapter import LocalDBResponseAdapter
|
5
5
|
|
6
|
-
class
|
6
|
+
class ResponseResourceFactory():
|
7
7
|
|
8
8
|
def __init__(self, settings: RemoteSettings):
|
9
9
|
self.__remote_settings = settings
|
@@ -3,7 +3,7 @@ from stoobly_agent.lib.orm.request import Request
|
|
3
3
|
|
4
4
|
from .local_db.response_header_adapter import LocalDBResponseHeaderAdapter
|
5
5
|
|
6
|
-
class
|
6
|
+
class ResponseHeaderResourceFactory():
|
7
7
|
|
8
8
|
def __init__(self, settings: RemoteSettings):
|
9
9
|
self.__remote_settings = settings
|
stoobly_agent/app/models/{adapters/scenario_adapter_factory.py → factories/resource/scenario.py}
RENAMED
@@ -3,9 +3,9 @@ from stoobly_agent.lib.api.scenarios_resource import ScenariosResource
|
|
3
3
|
from stoobly_agent.app.settings import RemoteSettings
|
4
4
|
|
5
5
|
from .local_db.scenario_adapter import LocalDBScenarioAdapter
|
6
|
-
from .
|
6
|
+
from .stoobly.scenario_adapter import StooblyScenarioAdapter
|
7
7
|
|
8
|
-
class
|
8
|
+
class ScenarioResourceFactory():
|
9
9
|
|
10
10
|
def __init__(self, settings: RemoteSettings):
|
11
11
|
self.__remote_settings = settings
|
File without changes
|
@@ -1,11 +1,10 @@
|
|
1
1
|
import pdb
|
2
2
|
import requests
|
3
3
|
|
4
|
+
from stoobly_agent.app.models.types import RequestCreateParams, RequestShowParams
|
4
5
|
from stoobly_agent.lib.api.requests_resource import RequestsResource
|
5
6
|
from stoobly_agent.lib.api.interfaces import RequestShowResponse, RequestsIndexResponse
|
6
7
|
|
7
|
-
from .types import RequestCreateParams, RequestShowParams
|
8
|
-
|
9
8
|
class StooblyRequestAdapter():
|
10
9
|
|
11
10
|
def __init__(self, __api: RequestsResource):
|
@@ -1,10 +1,9 @@
|
|
1
1
|
import pdb
|
2
2
|
|
3
|
+
from stoobly_agent.app.models.types import ScenarioCreateParams
|
3
4
|
from stoobly_agent.lib.api.scenarios_resource import ScenariosResource
|
4
5
|
from stoobly_agent.lib.api.interfaces.scenarios import ScenarioShowResponse, ScenariosIndexResponse
|
5
6
|
|
6
|
-
from .types import ScenarioCreateParams
|
7
|
-
|
8
7
|
class StooblyScenarioAdapter():
|
9
8
|
|
10
9
|
def __init__(self, __api: ScenariosResource):
|
@@ -2,12 +2,12 @@ import pdb
|
|
2
2
|
import requests
|
3
3
|
|
4
4
|
from typing import Union
|
5
|
-
from stoobly_agent.app.models.adapters.header_adapter_factory import HeaderAdapterFactory
|
6
5
|
|
7
6
|
from stoobly_agent.app.models.types.request_components import HeaderIndexResponse
|
8
7
|
from stoobly_agent.app.settings import Settings
|
9
8
|
from stoobly_agent.lib.logger import Logger
|
10
9
|
|
10
|
+
from .factories.resource.header import HeaderResourceFactory
|
11
11
|
from .model import Model
|
12
12
|
|
13
13
|
class HeaderModel(Model):
|
@@ -16,7 +16,7 @@ class HeaderModel(Model):
|
|
16
16
|
super().__init__(settings)
|
17
17
|
|
18
18
|
def as_local(self):
|
19
|
-
self.adapter =
|
19
|
+
self.adapter = HeaderResourceFactory(self.settings.remote).local_db()
|
20
20
|
|
21
21
|
def as_remote(self):
|
22
22
|
# raise('Not yet supported.')
|
@@ -7,7 +7,7 @@ from stoobly_agent.app.models.types.request_components import QueryParamIndexRes
|
|
7
7
|
from stoobly_agent.app.settings import Settings
|
8
8
|
from stoobly_agent.lib.logger import Logger
|
9
9
|
|
10
|
-
from .
|
10
|
+
from .factories.resource.query_param import QueryParamResourceFactory
|
11
11
|
from .model import Model
|
12
12
|
|
13
13
|
class QueryParamModel(Model):
|
@@ -16,7 +16,7 @@ class QueryParamModel(Model):
|
|
16
16
|
super().__init__(settings)
|
17
17
|
|
18
18
|
def as_local(self):
|
19
|
-
self.adapter =
|
19
|
+
self.adapter = QueryParamResourceFactory(self.settings.remote).local_db()
|
20
20
|
|
21
21
|
def as_remote(self):
|
22
22
|
#raise('Not yet supported.')
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import pdb
|
2
2
|
import requests
|
3
3
|
|
4
|
-
from stoobly_agent.app.models.adapters.replayed_response_adapter_factory import ReplayedResponseAdapterFactory
|
5
4
|
from stoobly_agent.app.settings import Settings
|
6
5
|
from stoobly_agent.lib.logger import Logger
|
7
6
|
|
7
|
+
from .factories.resource.replayed_response import ReplayedResponseResourceFactory
|
8
8
|
from .model import Model
|
9
9
|
|
10
10
|
class ReplayedResponseModel(Model):
|
@@ -13,7 +13,7 @@ class ReplayedResponseModel(Model):
|
|
13
13
|
super().__init__(settings)
|
14
14
|
|
15
15
|
def as_local(self):
|
16
|
-
self.adapter =
|
16
|
+
self.adapter = ReplayedResponseResourceFactory(self.settings.remote).local_db()
|
17
17
|
|
18
18
|
def as_remote(self):
|
19
19
|
# raise('Not yet supported.')
|
@@ -8,10 +8,9 @@ from stoobly_agent.app.settings import Settings
|
|
8
8
|
from stoobly_agent.lib.api.interfaces import RequestShowResponse
|
9
9
|
from stoobly_agent.lib.logger import Logger
|
10
10
|
|
11
|
-
from .
|
12
|
-
from .adapters.types import RequestCreateParams, RequestShowParams
|
11
|
+
from .factories.resource.request import RequestResourceFactory
|
13
12
|
from .model import Model
|
14
|
-
from .types
|
13
|
+
from .types import RequestCreateParams, RequestShowParams, RequestsModelIndex
|
15
14
|
|
16
15
|
class RequestModel(Model):
|
17
16
|
|
@@ -19,10 +18,10 @@ class RequestModel(Model):
|
|
19
18
|
super().__init__(settings)
|
20
19
|
|
21
20
|
def as_local(self):
|
22
|
-
self.adapter =
|
21
|
+
self.adapter = RequestResourceFactory(self.settings.remote).local_db()
|
23
22
|
|
24
23
|
def as_remote(self):
|
25
|
-
self.adapter =
|
24
|
+
self.adapter = RequestResourceFactory(self.settings.remote).stoobly()
|
26
25
|
|
27
26
|
def create(self, **body_params: RequestCreateParams) -> Union[RequestsModelIndex, None]:
|
28
27
|
try:
|
@@ -7,7 +7,7 @@ from stoobly_agent.app.models.types.request_components import ResponseHeaderInde
|
|
7
7
|
from stoobly_agent.app.settings import Settings
|
8
8
|
from stoobly_agent.lib.logger import Logger
|
9
9
|
|
10
|
-
from .
|
10
|
+
from .factories.resource.response_header import ResponseHeaderResourceFactory
|
11
11
|
from .model import Model
|
12
12
|
|
13
13
|
class ResponseHeaderModel(Model):
|
@@ -16,7 +16,7 @@ class ResponseHeaderModel(Model):
|
|
16
16
|
super().__init__(settings)
|
17
17
|
|
18
18
|
def as_local(self):
|
19
|
-
self.adapter =
|
19
|
+
self.adapter = ResponseHeaderResourceFactory(self.settings.remote).local_db()
|
20
20
|
|
21
21
|
def as_remote(self):
|
22
22
|
# raise('Not yet supported.')
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import pdb
|
2
2
|
import requests
|
3
3
|
|
4
|
-
from stoobly_agent.app.models.adapters.response_adapter_factory import ResponseAdapterFactory
|
5
4
|
from stoobly_agent.app.settings import Settings
|
6
5
|
from stoobly_agent.lib.logger import Logger
|
7
6
|
|
7
|
+
from .factories.resource.response import ResponseResourceFactory
|
8
8
|
from .model import Model
|
9
9
|
|
10
10
|
class ResponseModel(Model):
|
@@ -13,7 +13,7 @@ class ResponseModel(Model):
|
|
13
13
|
super().__init__(settings)
|
14
14
|
|
15
15
|
def as_local(self):
|
16
|
-
self.adapter =
|
16
|
+
self.adapter = ResponseResourceFactory(self.settings.remote).local_db()
|
17
17
|
|
18
18
|
def as_remote(self):
|
19
19
|
# raise('Not yet supported.')
|
@@ -7,8 +7,8 @@ from stoobly_agent.lib.logger import Logger
|
|
7
7
|
from stoobly_agent.lib.api.interfaces.scenarios import ScenarioShowResponse, ScenariosIndexResponse
|
8
8
|
from stoobly_agent.app.settings import Settings
|
9
9
|
|
10
|
-
from .
|
11
|
-
from .
|
10
|
+
from .types import ScenarioCreateParams
|
11
|
+
from .factories.resource.scenario import ScenarioResourceFactory
|
12
12
|
from .model import Model
|
13
13
|
|
14
14
|
class ScenarioModel(Model):
|
@@ -17,10 +17,10 @@ class ScenarioModel(Model):
|
|
17
17
|
super().__init__(settings)
|
18
18
|
|
19
19
|
def as_local(self):
|
20
|
-
self.adapter =
|
20
|
+
self.adapter = ScenarioResourceFactory(self.settings.remote).local_db()
|
21
21
|
|
22
22
|
def as_remote(self):
|
23
|
-
self.adapter =
|
23
|
+
self.adapter = ScenarioResourceFactory(self.settings.remote).stoobly()
|
24
24
|
|
25
25
|
def create(self, **body_params: ScenarioCreateParams) -> Union[ScenarioShowResponse, None]:
|
26
26
|
try:
|
@@ -96,6 +96,10 @@ class Request():
|
|
96
96
|
def headers(self, v: MultiDict):
|
97
97
|
self.__set_dict('headers', v)
|
98
98
|
|
99
|
+
@property
|
100
|
+
def query(self) -> str:
|
101
|
+
return urlencode(self.query_params)
|
102
|
+
|
99
103
|
@property
|
100
104
|
def query_params(self) -> MultiDict:
|
101
105
|
query_params = MultiDict()
|
@@ -115,7 +119,10 @@ class Request():
|
|
115
119
|
if not encoded_body:
|
116
120
|
return ''
|
117
121
|
|
118
|
-
|
122
|
+
try:
|
123
|
+
return base64.b64decode(encoded_body)
|
124
|
+
except Exception as e:
|
125
|
+
return encoded_body
|
119
126
|
|
120
127
|
@body.setter
|
121
128
|
def body(self, v: Union[bytes, str]):
|
@@ -83,10 +83,6 @@ def __commit_options(options: dict):
|
|
83
83
|
if options.get('proxy_host') and options.get('proxy_port'):
|
84
84
|
settings.proxy.url = f"http://{options.get('proxy_host')}:{options.get('proxy_port')}"
|
85
85
|
|
86
|
-
if options.get('intercept_mode'):
|
87
|
-
settings.proxy.intercept.mode = options['intercept_mode']
|
88
|
-
settings.proxy.intercept.active = True
|
89
|
-
|
90
86
|
settings.ui.active = not options.get('headless')
|
91
87
|
|
92
88
|
settings.commit()
|
@@ -112,7 +108,6 @@ def __filter_options(options):
|
|
112
108
|
if 'ui_port' in options:
|
113
109
|
del options['ui_port']
|
114
110
|
|
115
|
-
del options['intercept_mode']
|
116
111
|
del options['log_level']
|
117
112
|
del options['proxy_host']
|
118
113
|
del options['proxy_mode']
|
@@ -2,15 +2,12 @@ import requests
|
|
2
2
|
import time
|
3
3
|
import pdb
|
4
4
|
|
5
|
-
from mitmproxy.http import HTTPFlow as MitmproxyHTTPFlow
|
6
5
|
from mitmproxy.http import Request as MitmproxyRequest
|
7
6
|
from typing import Callable, TypedDict
|
8
7
|
|
9
8
|
from stoobly_agent.app.models.request_model import RequestModel
|
10
|
-
from stoobly_agent.app.proxy.intercept_settings import InterceptSettings
|
11
9
|
from stoobly_agent.app.proxy.mitmproxy.request_facade import MitmproxyRequestFacade
|
12
10
|
from stoobly_agent.app.proxy.utils.rewrite_rules_to_ignored_components_service import rewrite_rules_to_ignored_components
|
13
|
-
from stoobly_agent.app.settings import intercept_settings
|
14
11
|
from stoobly_agent.config.constants import custom_headers, mock_policy
|
15
12
|
from stoobly_agent.lib.logger import Logger
|
16
13
|
|
@@ -13,7 +13,7 @@ from stoobly_agent.lib.logger import Logger
|
|
13
13
|
|
14
14
|
from .handle_mock_service import handle_request_mock_generic
|
15
15
|
from .mock.context import MockContext
|
16
|
-
from .test.
|
16
|
+
from .test.context_abc import TestContextABC as TestContext
|
17
17
|
from .test.test_service import test
|
18
18
|
from .upload.upload_test_service import inject_upload_test
|
19
19
|
|