stoobly-agent 0.21.0__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 +51 -29
- 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 +225 -135
- stoobly_agent/app/cli/dev_tools_cli.py +3 -1
- stoobly_agent/app/cli/helpers/__init__.py +2 -1
- 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 +8 -0
- stoobly_agent/app/cli/helpers/scenario_facade.py +10 -28
- stoobly_agent/app/cli/intercept.py +46 -2
- stoobly_agent/app/cli/main_group.py +8 -9
- stoobly_agent/app/cli/project_cli.py +10 -27
- stoobly_agent/app/cli/request_cli.py +14 -18
- stoobly_agent/app/cli/scenario_cli.py +94 -87
- 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_request_adapter.py +19 -12
- stoobly_agent/app/models/adapters/raw_http_response_adapter.py +22 -12
- 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/header_adapter.py +2 -2
- 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/mock/hashed_request_decorator.py +2 -2
- stoobly_agent/app/proxy/replay/replay_request_service.py +58 -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/app/settings/data_settings.py +3 -1
- stoobly_agent/cli.py +89 -11
- stoobly_agent/config/constants/env_vars.py +2 -1
- stoobly_agent/config/data_dir.py +29 -8
- stoobly_agent/config/settings.yml.sample +1 -1
- stoobly_agent/db/migrations/2022_12_12_092437_align_requests.py +4 -4
- 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 +13 -0
- stoobly_agent/lib/api/keys/resource_key.py +5 -3
- stoobly_agent/lib/api/scenarios_resource.py +4 -12
- stoobly_agent/lib/api/stoobly_api.py +9 -5
- stoobly_agent/lib/orm/__init__.py +1 -1
- stoobly_agent/lib/orm/migrate_service.py +28 -13
- 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 +15 -24
- 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.0.dist-info → stoobly_agent-0.22.3.dist-info}/METADATA +1 -1
- {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/RECORD +186 -168
- {stoobly_agent-0.21.0.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/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.0.dist-info → stoobly_agent-0.22.3.dist-info}/LICENSE +0 -0
- {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/entry_points.txt +0 -0
- {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,155 @@
|
|
1
|
+
import abc
|
2
|
+
|
3
|
+
from mitmproxy.http import Request
|
4
|
+
from typing import Union
|
5
|
+
|
6
|
+
from stoobly_agent.app.proxy.test.helpers.endpoint_facade import EndpointFacade
|
7
|
+
from stoobly_agent.app.proxy.test.helpers.request_component_names_facade import RequestComponentNamesFacade
|
8
|
+
|
9
|
+
from stoobly_agent.lib.api.interfaces.endpoints import EndpointShowResponse
|
10
|
+
from stoobly_agent.lib.orm.trace import Trace
|
11
|
+
|
12
|
+
from .context_response import TestContextResponse
|
13
|
+
|
14
|
+
FuzzyContent = Union[dict, list, str]
|
15
|
+
|
16
|
+
class TestContextABC(abc.ABC):
|
17
|
+
|
18
|
+
@abc.abstractmethod
|
19
|
+
def with_endpoints_resource(self, resource: EndpointShowResponse):
|
20
|
+
pass
|
21
|
+
|
22
|
+
@property
|
23
|
+
@abc.abstractmethod
|
24
|
+
def cached_expected_response_content(self) -> Union[bytes, None, str]:
|
25
|
+
pass
|
26
|
+
|
27
|
+
@property
|
28
|
+
@abc.abstractmethod
|
29
|
+
def endpoint(self) -> EndpointFacade:
|
30
|
+
pass
|
31
|
+
|
32
|
+
@property
|
33
|
+
@abc.abstractmethod
|
34
|
+
def lifecycle_hooks(self):
|
35
|
+
pass
|
36
|
+
|
37
|
+
@property
|
38
|
+
@abc.abstractmethod
|
39
|
+
def lifecycle_hooks_script_path(self):
|
40
|
+
pass
|
41
|
+
|
42
|
+
@property
|
43
|
+
@abc.abstractmethod
|
44
|
+
def end_time(self):
|
45
|
+
pass
|
46
|
+
|
47
|
+
@property
|
48
|
+
@abc.abstractmethod
|
49
|
+
def expected_response(self) -> TestContextResponse:
|
50
|
+
pass
|
51
|
+
|
52
|
+
@property
|
53
|
+
@abc.abstractmethod
|
54
|
+
def decoded_response_content(self) -> FuzzyContent:
|
55
|
+
pass
|
56
|
+
|
57
|
+
@property
|
58
|
+
@abc.abstractmethod
|
59
|
+
def decoded_expected_response_content(self) -> FuzzyContent:
|
60
|
+
pass
|
61
|
+
|
62
|
+
@property
|
63
|
+
@abc.abstractmethod
|
64
|
+
def filter(self):
|
65
|
+
pass
|
66
|
+
|
67
|
+
@property
|
68
|
+
@abc.abstractmethod
|
69
|
+
def flow(self):
|
70
|
+
pass
|
71
|
+
|
72
|
+
@property
|
73
|
+
@abc.abstractmethod
|
74
|
+
def intercept_settings(self):
|
75
|
+
pass
|
76
|
+
|
77
|
+
@property
|
78
|
+
@abc.abstractmethod
|
79
|
+
def log(self):
|
80
|
+
pass
|
81
|
+
|
82
|
+
@log.setter
|
83
|
+
@abc.abstractmethod
|
84
|
+
def log(self, v: str):
|
85
|
+
pass
|
86
|
+
|
87
|
+
@property
|
88
|
+
@abc.abstractmethod
|
89
|
+
def mock_request_id(self) -> Union[str, None]:
|
90
|
+
pass
|
91
|
+
|
92
|
+
@property
|
93
|
+
@abc.abstractmethod
|
94
|
+
def mock_request_endpoint_id(self) -> Union[str, None]:
|
95
|
+
pass
|
96
|
+
|
97
|
+
@property
|
98
|
+
@abc.abstractmethod
|
99
|
+
def passed(self):
|
100
|
+
pass
|
101
|
+
|
102
|
+
@passed.setter
|
103
|
+
@abc.abstractmethod
|
104
|
+
def passed(self, v):
|
105
|
+
pass
|
106
|
+
|
107
|
+
@property
|
108
|
+
@abc.abstractmethod
|
109
|
+
def request(self) -> Request:
|
110
|
+
pass
|
111
|
+
|
112
|
+
@property
|
113
|
+
@abc.abstractmethod
|
114
|
+
def request_headers(self):
|
115
|
+
pass
|
116
|
+
|
117
|
+
@property
|
118
|
+
@abc.abstractmethod
|
119
|
+
def response(self) -> TestContextResponse:
|
120
|
+
pass
|
121
|
+
|
122
|
+
@property
|
123
|
+
@abc.abstractmethod
|
124
|
+
def response_param_names(self) -> RequestComponentNamesFacade:
|
125
|
+
pass
|
126
|
+
|
127
|
+
@property
|
128
|
+
@abc.abstractmethod
|
129
|
+
def rewritten_expected_response_content(self):
|
130
|
+
pass
|
131
|
+
|
132
|
+
@property
|
133
|
+
@abc.abstractmethod
|
134
|
+
def skipped(self):
|
135
|
+
pass
|
136
|
+
|
137
|
+
@skipped.setter
|
138
|
+
@abc.abstractmethod
|
139
|
+
def skipped(self, v: bool):
|
140
|
+
pass
|
141
|
+
|
142
|
+
@property
|
143
|
+
@abc.abstractmethod
|
144
|
+
def start_time(self):
|
145
|
+
pass
|
146
|
+
|
147
|
+
@property
|
148
|
+
@abc.abstractmethod
|
149
|
+
def strategy(self):
|
150
|
+
pass
|
151
|
+
|
152
|
+
@property
|
153
|
+
@abc.abstractmethod
|
154
|
+
def trace(self) -> Union[Trace, None]:
|
155
|
+
pass
|
@@ -2,7 +2,7 @@ import pdb
|
|
2
2
|
|
3
3
|
from typing import Iterable, List, TypedDict, Union
|
4
4
|
|
5
|
-
from stoobly_agent.app.proxy.test.
|
5
|
+
from stoobly_agent.app.proxy.test.context_abc import TestContextABC as TestContext
|
6
6
|
from stoobly_agent.app.proxy.test.helpers.request_component_names_facade import RequestComponentNamesFacade
|
7
7
|
from stoobly_agent.lib.api.interfaces.endpoints import RequestComponentName, ResponseParamName
|
8
8
|
from stoobly_agent.lib.utils.python_to_ruby_type import convert
|
@@ -5,7 +5,7 @@ from typing import List, Tuple, TypedDict, Union
|
|
5
5
|
from stoobly_agent.app.proxy.test.helpers.request_component_names_facade import RequestComponentNamesFacade
|
6
6
|
from stoobly_agent.lib.api.interfaces.endpoints import RequestComponentName
|
7
7
|
|
8
|
-
from ..
|
8
|
+
from ..context_abc import TestContextABC as TestContext
|
9
9
|
from .context import MatchContext, build_match_context
|
10
10
|
from .errors import length_match_error, param_name_exists_error, param_name_missing_error, type_match_error, valid_type_error
|
11
11
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import pdb
|
2
2
|
|
3
3
|
from typing import Tuple
|
4
|
-
from stoobly_agent.app.proxy.test.
|
4
|
+
from stoobly_agent.app.proxy.test.context_abc import TestContextABC as TestContext
|
5
5
|
|
6
6
|
from stoobly_agent.app.proxy.test.helpers.request_component_names_facade import RequestComponentNamesFacade
|
7
7
|
from stoobly_agent.app.proxy.test.matchers.errors import length_match_error, param_name_missing_error, type_match_error, value_match_error
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import pdb
|
2
2
|
|
3
3
|
from typing import Iterable, Tuple
|
4
|
-
from stoobly_agent.app.proxy.test.
|
4
|
+
from stoobly_agent.app.proxy.test.context_abc import TestContextABC as TestContext
|
5
5
|
from stoobly_agent.app.proxy.test.helpers.request_component_names_facade import RequestComponentNamesFacade
|
6
6
|
from stoobly_agent.app.proxy.test.matchers.errors import param_name_missing_error, type_match_error, valid_type_error
|
7
7
|
|
@@ -4,7 +4,7 @@ from stoobly_agent.app.proxy.replay.body_parser_service import decode_response,
|
|
4
4
|
|
5
5
|
from stoobly_agent.config.constants import test_strategy
|
6
6
|
|
7
|
-
from .
|
7
|
+
from .context_abc import TestContextABC as TestContext
|
8
8
|
from .matchers.custom import matches as custom_matches
|
9
9
|
from .matchers.contract import matches as contract_matches
|
10
10
|
from .matchers.diff import matches as diff_matches
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from ..mitmproxy.request_facade import MitmproxyRequestFacade
|
2
2
|
|
3
3
|
class ProxyRequest:
|
4
|
-
def __init__(self, request: MitmproxyRequestFacade, upstream_url: str):
|
4
|
+
def __init__(self, request: MitmproxyRequestFacade, upstream_url: str = None):
|
5
5
|
self.request = request
|
6
6
|
|
7
7
|
self.upstream_url = upstream_url
|
@@ -9,4 +9,7 @@ class ProxyRequest:
|
|
9
9
|
def url(self):
|
10
10
|
url = self.request.url
|
11
11
|
|
12
|
+
if not self.upstream_url:
|
13
|
+
return url
|
14
|
+
|
12
15
|
return url.replace(self.request.base_url, self.upstream_url)
|
@@ -14,7 +14,9 @@ class DataSettings:
|
|
14
14
|
self.__data_rules_map = {k: DataRules(v) for k, v in self.__data_settings.items()}
|
15
15
|
|
16
16
|
def data_rules(self, project_id: str) -> DataRules:
|
17
|
-
|
17
|
+
if not self.__data_rules_map.get(project_id):
|
18
|
+
self.__data_rules_map[project_id] = DataRules({})
|
19
|
+
return self.__data_rules_map[project_id]
|
18
20
|
|
19
21
|
def to_dict(self):
|
20
22
|
return {k: v.to_dict() for k, v in self.__data_rules_map.items()}
|
stoobly_agent/cli.py
CHANGED
@@ -1,14 +1,21 @@
|
|
1
1
|
import click
|
2
2
|
import os
|
3
3
|
import pdb
|
4
|
+
import requests
|
4
5
|
import sys
|
5
6
|
|
6
|
-
from stoobly_agent
|
7
|
+
from stoobly_agent import VERSION
|
8
|
+
from stoobly_agent.app.cli.helpers.context import ReplayContext
|
9
|
+
from stoobly_agent.app.cli.helpers.handle_mock_service import print_raw_response, RAW_FORMAT
|
10
|
+
from stoobly_agent.app.proxy.constants import custom_response_codes
|
11
|
+
from stoobly_agent.app.proxy.replay.replay_request_service import replay as replay_request
|
12
|
+
from stoobly_agent.config.constants import env_vars, mode
|
13
|
+
from stoobly_agent.config.data_dir import DataDir
|
7
14
|
from stoobly_agent.lib.utils.conditional_decorator import ConditionalDecorator
|
8
15
|
|
9
16
|
from .app.api import run as run_api
|
10
|
-
from .app.cli import ca_cert, config, feature, intercept, MainGroup,
|
11
|
-
from .app.proxy import CONNECTION_STRATEGIES,
|
17
|
+
from .app.cli import ca_cert, config, feature, intercept, MainGroup, request, scenario, trace
|
18
|
+
from .app.proxy import CONNECTION_STRATEGIES, run as run_proxy
|
12
19
|
from .app.settings import Settings
|
13
20
|
from .lib import logger
|
14
21
|
from .lib.orm.migrate_service import migrate as migrate_database
|
@@ -16,6 +23,9 @@ from .lib.orm.migrate_service import migrate as migrate_database
|
|
16
23
|
settings = Settings.instance()
|
17
24
|
is_remote = settings.cli.features.remote
|
18
25
|
|
26
|
+
# Makes sure database is up to date
|
27
|
+
migrate_database(VERSION)
|
28
|
+
|
19
29
|
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
|
20
30
|
|
21
31
|
@click.version_option()
|
@@ -34,6 +44,7 @@ main.add_command(config)
|
|
34
44
|
main.add_command(feature)
|
35
45
|
main.add_command(intercept)
|
36
46
|
main.add_command(request)
|
47
|
+
main.add_command(scenario)
|
37
48
|
main.add_command(trace)
|
38
49
|
|
39
50
|
if settings.cli.features.dev_tools:
|
@@ -45,10 +56,15 @@ if settings.cli.features.exec:
|
|
45
56
|
ExecDecorator(main).decorate()
|
46
57
|
|
47
58
|
if settings.cli.features.remote:
|
48
|
-
from .app.cli import
|
59
|
+
from .app.cli import project, report
|
49
60
|
main.add_command(project)
|
50
61
|
main.add_command(report)
|
51
|
-
|
62
|
+
|
63
|
+
@main.command(
|
64
|
+
help="Initialize a new context"
|
65
|
+
)
|
66
|
+
def init(**kwargs):
|
67
|
+
DataDir.instance().create()
|
52
68
|
|
53
69
|
@main.command(
|
54
70
|
help="Run proxy and/or UI",
|
@@ -56,7 +72,6 @@ if settings.cli.features.remote:
|
|
56
72
|
@ConditionalDecorator(lambda f: click.option('--api-url', help='API URL.')(f), is_remote)
|
57
73
|
@click.option('--headless', is_flag=True, default=False, help='Disable starting UI.')
|
58
74
|
@click.option('--connection-strategy', help=', '.join(CONNECTION_STRATEGIES), type=click.Choice(CONNECTION_STRATEGIES))
|
59
|
-
@click.option('--intercept-mode', help=', '.join(INTERCEPT_MODES), type=click.Choice(INTERCEPT_MODES))
|
60
75
|
@click.option('--log-level', default=logger.INFO, type=click.Choice([logger.DEBUG, logger.INFO, logger.WARNING, logger.ERROR]), help='''
|
61
76
|
Log levels can be "debug", "info", "warning", or "error"
|
62
77
|
''')
|
@@ -83,10 +98,73 @@ def run(**kwargs):
|
|
83
98
|
if 'headless' in kwargs and not kwargs['headless']:
|
84
99
|
run_api(**kwargs)
|
85
100
|
|
86
|
-
|
87
|
-
print(f"Error: Invalid value for --intercept-mode, values: {', '.join(INTERCEPT_MODES)}", file=sys.stderr)
|
88
|
-
sys.exit(1)
|
101
|
+
run_proxy(**kwargs)
|
89
102
|
|
90
|
-
|
103
|
+
@main.command(
|
104
|
+
help="Mock request"
|
105
|
+
)
|
106
|
+
@click.option('-d', '--data', default='', help='HTTP POST data')
|
107
|
+
@click.option('--format', type=click.Choice([RAW_FORMAT]), help='Format response')
|
108
|
+
@click.option('-H', '--header', multiple=True, help='Pass custom header(s) to server')
|
109
|
+
@ConditionalDecorator(lambda f: click.option('--project-key')(f), is_remote)
|
110
|
+
@click.option('-X', '--request', default='GET', help='Specify request command to use')
|
111
|
+
@click.option('--scenario-key')
|
112
|
+
@click.argument('url')
|
113
|
+
def mock(**kwargs):
|
114
|
+
request = __build_request_from_curl(**kwargs)
|
115
|
+
|
116
|
+
context = ReplayContext.from_python_request(request)
|
117
|
+
response: requests.Response = replay_request(context, {
|
118
|
+
**kwargs,
|
119
|
+
'mode': mode.MOCK,
|
120
|
+
})
|
121
|
+
|
122
|
+
if response.status_code == custom_response_codes.NOT_FOUND:
|
123
|
+
print(f"Error: {response.content.decode()}")
|
124
|
+
sys.exit(1)
|
125
|
+
|
126
|
+
if kwargs['format'] == RAW_FORMAT:
|
127
|
+
print_raw_response(response)
|
128
|
+
else:
|
129
|
+
print(response.content.decode())
|
91
130
|
|
92
|
-
|
131
|
+
@main.command(
|
132
|
+
help="Record request"
|
133
|
+
)
|
134
|
+
@click.option('-d', '--data', default='', help='HTTP POST data')
|
135
|
+
@click.option('--format', type=click.Choice([RAW_FORMAT]), help='Format response')
|
136
|
+
@click.option('-H', '--header', multiple=True, help='Pass custom header(s) to server')
|
137
|
+
@ConditionalDecorator(lambda f: click.option('--project-key')(f), is_remote)
|
138
|
+
@click.option('-X', '--request', default='GET', help='Specify request command to use')
|
139
|
+
@click.option('--scenario-key')
|
140
|
+
@click.argument('url')
|
141
|
+
def record(**kwargs):
|
142
|
+
request = __build_request_from_curl(**kwargs)
|
143
|
+
|
144
|
+
context = ReplayContext.from_python_request(request)
|
145
|
+
response: requests.Response = replay_request(context, {
|
146
|
+
**kwargs,
|
147
|
+
'mode': mode.RECORD,
|
148
|
+
})
|
149
|
+
|
150
|
+
if kwargs['format'] == RAW_FORMAT:
|
151
|
+
print_raw_response(response)
|
152
|
+
else:
|
153
|
+
print(response.content.decode())
|
154
|
+
|
155
|
+
def __build_request_from_curl(**kwargs):
|
156
|
+
headers = {}
|
157
|
+
for header in kwargs['header']:
|
158
|
+
toks = header.split(':')
|
159
|
+
|
160
|
+
if len(toks) != 2:
|
161
|
+
continue
|
162
|
+
|
163
|
+
headers[toks[0]] = toks[1]
|
164
|
+
|
165
|
+
return requests.Request(
|
166
|
+
data=kwargs['data'],
|
167
|
+
headers=headers,
|
168
|
+
method=kwargs['request'],
|
169
|
+
url=kwargs['url']
|
170
|
+
)
|
@@ -1,8 +1,9 @@
|
|
1
1
|
AGENT_ACTIVE_MODE = 'STOOBLY_AGENT_ACTIVE_MODE'
|
2
2
|
AGENT_CONFIG_PATH = 'STOOBLY_AGENT_CONFIG_PATH'
|
3
3
|
AGENT_ENABLED = 'STOOBLY_AGENT_ENABLED'
|
4
|
-
|
4
|
+
AGENT_SELF_INTERCEPT_ENABLED = 'STOOBLY_AGENT_SELF_INTERCEPT_ENABLED'
|
5
5
|
AGENT_INCLUDE_PATTERNS = 'STOOBLY_AGENT_INCLUDE_PATTERNS'
|
6
|
+
AGENT_IS_HEADLESS = 'STOOBLY_AGENT_IS_HEADLESS'
|
6
7
|
AGENT_EXCLUDE_PATTERNS = 'STOOBLY_AGENT_EXCLUDE_PATTERNS'
|
7
8
|
AGENT_POLICY = 'STOOBLY_AGENT_POLICY'
|
8
9
|
AGENT_PROJECT_KEY = 'STOOBLY_AGENT_PROJECT_KEY'
|
stoobly_agent/config/data_dir.py
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
import os
|
2
2
|
import pdb
|
3
|
-
|
3
|
+
|
4
|
+
from stoobly_agent.config.constants.env_vars import ENV
|
4
5
|
|
5
6
|
class DataDir:
|
6
7
|
DATA_DIR_NAME = '.stoobly'
|
7
8
|
DB_FILE_NAME = 'stoobly_agent.sqlite3'
|
9
|
+
DB_VERSION_NAME = 'VERSION'
|
8
10
|
|
9
11
|
_instance = None
|
10
12
|
|
@@ -12,11 +14,15 @@ class DataDir:
|
|
12
14
|
if DataDir._instance:
|
13
15
|
raise RuntimeError('Call instance() instead')
|
14
16
|
else:
|
15
|
-
self.__data_dir_path = os.path.join(os.
|
17
|
+
self.__data_dir_path = os.path.join(os.getcwd(), self.DATA_DIR_NAME)
|
16
18
|
|
19
|
+
# If the current working directory does not contain a .stoobly folder, default to home directory
|
17
20
|
if not os.path.exists(self.__data_dir_path):
|
18
|
-
os.
|
21
|
+
self.__data_dir_path = os.path.join(os.path.expanduser('~'), self.DATA_DIR_NAME)
|
19
22
|
|
23
|
+
if not os.path.exists(self.__data_dir_path):
|
24
|
+
os.makedirs(self.__data_dir_path, exist_ok=True)
|
25
|
+
|
20
26
|
@classmethod
|
21
27
|
def instance(cls):
|
22
28
|
if cls._instance is None:
|
@@ -26,6 +32,13 @@ class DataDir:
|
|
26
32
|
|
27
33
|
@property
|
28
34
|
def path(self):
|
35
|
+
if os.environ.get(ENV) == 'test':
|
36
|
+
test_path = os.path.join(self.__data_dir_path, 'tmp', self.DATA_DIR_NAME)
|
37
|
+
|
38
|
+
if not os.path.exists(test_path):
|
39
|
+
os.makedirs(test_path, exist_ok=True)
|
40
|
+
return test_path
|
41
|
+
|
29
42
|
return self.__data_dir_path
|
30
43
|
|
31
44
|
@property
|
@@ -46,15 +59,23 @@ class DataDir:
|
|
46
59
|
|
47
60
|
return db_dir_path
|
48
61
|
|
49
|
-
@property
|
50
|
-
def tmp_db_file_path(self):
|
51
|
-
tmp = tempfile.NamedTemporaryFile(delete=False)
|
52
|
-
return tmp.name
|
53
|
-
|
54
62
|
@property
|
55
63
|
def db_file_path(self):
|
56
64
|
return os.path.join(self.db_dir_path, self.DB_FILE_NAME)
|
57
65
|
|
66
|
+
@property
|
67
|
+
def db_version_path(self):
|
68
|
+
return os.path.join(self.db_dir_path, self.DB_VERSION_NAME)
|
69
|
+
|
58
70
|
@property
|
59
71
|
def settings_file_path(self):
|
60
72
|
return os.path.join(self.path, 'settings.yml')
|
73
|
+
|
74
|
+
def create(self, directoy_path = None):
|
75
|
+
if not directoy_path:
|
76
|
+
directoy_path = os.getcwd()
|
77
|
+
|
78
|
+
self.__data_dir_path = os.path.join(directoy_path, self.DATA_DIR_NAME)
|
79
|
+
|
80
|
+
if not os.path.exists(self.__data_dir_path):
|
81
|
+
os.mkdir(self.__data_dir_path)
|
@@ -26,14 +26,14 @@ class AlignRequests(Migration):
|
|
26
26
|
_request: requests.Request = RawHttpRequestAdapter(request.raw)
|
27
27
|
|
28
28
|
parsed_url = urlparse(_request.url)
|
29
|
-
request.path = parsed_url.path
|
30
|
-
request.query = parsed_url.query
|
29
|
+
request.path = parsed_url.path
|
30
|
+
request.query = parsed_url.query
|
31
31
|
|
32
32
|
if parsed_url.username:
|
33
|
-
request.user = parsed_url.username
|
33
|
+
request.user = parsed_url.username
|
34
34
|
|
35
35
|
if parsed_url.password:
|
36
|
-
request.password = parsed_url.password
|
36
|
+
request.password = parsed_url.password
|
37
37
|
|
38
38
|
response = request.response
|
39
39
|
if response:
|
stoobly_agent/lib/api/api.py
CHANGED
@@ -44,16 +44,16 @@ class Api():
|
|
44
44
|
def set_proxy(self, val):
|
45
45
|
current = {}
|
46
46
|
|
47
|
-
current[HTTP_PROXY] = os.environ.get(HTTP_PROXY)
|
47
|
+
current[HTTP_PROXY] = os.environ.get(HTTP_PROXY) or ''
|
48
48
|
os.environ[HTTP_PROXY] = val
|
49
49
|
|
50
|
-
current[HTTPS_PROXY] = os.environ.get(HTTPS_PROXY)
|
50
|
+
current[HTTPS_PROXY] = os.environ.get(HTTPS_PROXY) or ''
|
51
51
|
os.environ[HTTPS_PROXY] = val
|
52
52
|
|
53
|
-
current[HTTP_PROXY.lower()] = os.environ.get(HTTP_PROXY.lower())
|
53
|
+
current[HTTP_PROXY.lower()] = os.environ.get(HTTP_PROXY.lower()) or ''
|
54
54
|
os.environ[HTTP_PROXY.lower()] = val
|
55
55
|
|
56
|
-
current[HTTPS_PROXY.lower()] = os.environ.get(HTTPS_PROXY.lower())
|
56
|
+
current[HTTPS_PROXY.lower()] = os.environ.get(HTTPS_PROXY.lower()) or ''
|
57
57
|
os.environ[HTTPS_PROXY.lower()] = val
|
58
58
|
|
59
59
|
return current
|
@@ -1,4 +1,5 @@
|
|
1
1
|
from .resource_key import ResourceKey
|
2
|
+
from .organization_key import LOCAL_ORGANIZATION_ID
|
2
3
|
|
3
4
|
LOCAL_PROJECT_ID = 0
|
4
5
|
|
@@ -16,6 +17,18 @@ class ProjectKey(ResourceKey):
|
|
16
17
|
if not self.organization_id:
|
17
18
|
raise InvalidProjectKey('Missing organization_id')
|
18
19
|
|
20
|
+
@property
|
21
|
+
@classmethod
|
22
|
+
def local_key(cls) -> str:
|
23
|
+
return cls.encode({
|
24
|
+
'i': LOCAL_PROJECT_ID,
|
25
|
+
'o': LOCAL_ORGANIZATION_ID,
|
26
|
+
})
|
27
|
+
|
28
|
+
@property
|
29
|
+
def is_local(self) -> bool:
|
30
|
+
return int(self.id) == LOCAL_PROJECT_ID
|
31
|
+
|
19
32
|
@property
|
20
33
|
def id(self) -> str:
|
21
34
|
return self.get('i')
|
@@ -1,11 +1,11 @@
|
|
1
1
|
import base64
|
2
2
|
import json
|
3
|
-
import random
|
4
|
-
import time
|
5
3
|
|
6
4
|
class ResourceKey():
|
7
5
|
|
8
6
|
def __init__(self, key):
|
7
|
+
self.__raw = key
|
8
|
+
|
9
9
|
try:
|
10
10
|
key = base64.b64decode(key)
|
11
11
|
except:
|
@@ -19,6 +19,9 @@ class ResourceKey():
|
|
19
19
|
except:
|
20
20
|
self.decoded_key = {}
|
21
21
|
|
22
|
+
@property
|
23
|
+
def raw(self):
|
24
|
+
return self.__raw
|
22
25
|
|
23
26
|
@staticmethod
|
24
27
|
def encode(data: dict):
|
@@ -26,7 +29,6 @@ class ResourceKey():
|
|
26
29
|
**data,
|
27
30
|
}).encode())
|
28
31
|
|
29
|
-
|
30
32
|
def get(self, k: str):
|
31
33
|
v = self.decoded_key.get(k)
|
32
34
|
return str(v) if v != None else None
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import requests
|
2
2
|
import urllib
|
3
3
|
|
4
|
+
from stoobly_agent.app.models.types import ScenarioCreateParams
|
5
|
+
|
4
6
|
from ..logger import Logger
|
5
7
|
from .interfaces.pagination_query_params import PaginationQueryParams
|
6
8
|
from .stoobly_api import StooblyApi
|
@@ -8,19 +10,9 @@ from .stoobly_api import StooblyApi
|
|
8
10
|
class ScenariosResource(StooblyApi):
|
9
11
|
SCENARIOS_ENDPOINT = 'scenarios'
|
10
12
|
|
11
|
-
def create(self,
|
13
|
+
def create(self, **params: ScenarioCreateParams):
|
12
14
|
url = f"{self.service_url}/{self.SCENARIOS_ENDPOINT}"
|
13
|
-
|
14
|
-
body = {
|
15
|
-
'project_id': project_id,
|
16
|
-
**params,
|
17
|
-
}
|
18
|
-
|
19
|
-
files = {}
|
20
|
-
if len(raw_requests) > 0:
|
21
|
-
files = { 'file': raw_requests }
|
22
|
-
|
23
|
-
return self.post(url, headers=self.default_headers, data=body, files=files)
|
15
|
+
return self.post(url, headers=self.default_headers, data=params)
|
24
16
|
|
25
17
|
def index(self, **query_params: PaginationQueryParams) -> requests.Response:
|
26
18
|
url = f"{self.service_url}/{self.SCENARIOS_ENDPOINT}"
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import base64
|
2
2
|
import json
|
3
|
-
import
|
4
|
-
import urllib
|
3
|
+
import os
|
5
4
|
import pdb
|
6
5
|
|
7
|
-
from
|
6
|
+
from stoobly_agent.config.constants import custom_headers, env_vars
|
7
|
+
|
8
8
|
from .api import Api
|
9
9
|
|
10
10
|
class StooblyApi(Api):
|
@@ -71,11 +71,15 @@ class StooblyApi(Api):
|
|
71
71
|
|
72
72
|
@property
|
73
73
|
def default_headers(self):
|
74
|
-
|
74
|
+
headers = {
|
75
75
|
'X-API-KEY': self.api_key,
|
76
|
-
'X-Do-Proxy': '1',
|
77
76
|
}
|
78
77
|
|
78
|
+
if not os.environ.get(env_vars.AGENT_SELF_INTERCEPT_ENABLED):
|
79
|
+
headers[custom_headers.DO_PROXY] = '1'
|
80
|
+
|
81
|
+
return headers
|
82
|
+
|
79
83
|
# Request
|
80
84
|
|
81
85
|
def from_project_key(self, project_key, handler):
|