stoobly-agent 1.9.0__py3-none-any.whl → 1.9.2__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 +1 -1
- stoobly_agent/app/models/factories/resource/local_db/helpers/log.py +69 -4
- stoobly_agent/app/models/factories/resource/local_db/helpers/request_snapshot.py +0 -1
- stoobly_agent/app/models/factories/resource/local_db/helpers/scenario_snapshot.py +2 -3
- stoobly_agent/app/models/factories/resource/local_db/helpers/snapshot_service.py +9 -8
- stoobly_agent/app/models/helpers/apply.py +9 -4
- stoobly_agent/app/proxy/handle_mock_service.py +15 -9
- stoobly_agent/app/proxy/mock/eval_fixtures_service.py +30 -24
- stoobly_agent/config/constants/custom_headers.py +1 -0
- stoobly_agent/lib/api/keys/uuid_key.py +4 -0
- stoobly_agent/test/app/cli/request/request_snapshot_test.py +54 -4
- stoobly_agent/test/app/cli/snapshot/snapshot_apply_test.py +263 -1
- stoobly_agent/test/app/cli/snapshot/snapshot_prune_test.py +72 -3
- stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
- {stoobly_agent-1.9.0.dist-info → stoobly_agent-1.9.2.dist-info}/METADATA +1 -1
- {stoobly_agent-1.9.0.dist-info → stoobly_agent-1.9.2.dist-info}/RECORD +19 -19
- {stoobly_agent-1.9.0.dist-info → stoobly_agent-1.9.2.dist-info}/LICENSE +0 -0
- {stoobly_agent-1.9.0.dist-info → stoobly_agent-1.9.2.dist-info}/WHEEL +0 -0
- {stoobly_agent-1.9.0.dist-info → stoobly_agent-1.9.2.dist-info}/entry_points.txt +0 -0
stoobly_agent/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
COMMAND = 'stoobly-agent'
|
2
|
-
VERSION = '1.9.
|
2
|
+
VERSION = '1.9.2'
|
@@ -8,6 +8,7 @@ from stoobly_agent.config.data_dir import DataDir
|
|
8
8
|
from stoobly_agent.lib.logger import bcolors, Logger
|
9
9
|
|
10
10
|
from .log_event import LogEvent
|
11
|
+
from .request_snapshot import RequestSnapshot
|
11
12
|
from .snapshot_types import DELETE_ACTION, PUT_ACTION, Resource
|
12
13
|
|
13
14
|
EVENT_DELIMITTER = "\n"
|
@@ -67,6 +68,10 @@ class Log():
|
|
67
68
|
contents = self.read()
|
68
69
|
return self.build_raw_events(contents)
|
69
70
|
|
71
|
+
@property
|
72
|
+
def scenario_inverted_index(self):
|
73
|
+
return self.build_scenario_inverted_index(self.target_events)
|
74
|
+
|
70
75
|
@property
|
71
76
|
def unprocessed_events(self) -> List[LogEvent]:
|
72
77
|
events = self.events
|
@@ -133,6 +138,22 @@ class Log():
|
|
133
138
|
|
134
139
|
def build_log_events(self, raw_events) -> List[LogEvent]:
|
135
140
|
return list(map(lambda raw_event: LogEvent(raw_event), raw_events))
|
141
|
+
|
142
|
+
def build_scenario_inverted_index(self, events: List[LogEvent], index = {}):
|
143
|
+
def handle_snapshot(snapshot: RequestSnapshot):
|
144
|
+
request_uuid = snapshot.uuid
|
145
|
+
if not request_uuid in index:
|
146
|
+
index[request_uuid] = []
|
147
|
+
|
148
|
+
index[request_uuid].append(event.resource_uuid)
|
149
|
+
|
150
|
+
for event in events:
|
151
|
+
if not event.is_scenario():
|
152
|
+
continue
|
153
|
+
|
154
|
+
event.snapshot().iter_request_snapshots(handle_snapshot)
|
155
|
+
|
156
|
+
return index
|
136
157
|
|
137
158
|
def next_version(self, last_processed_uuid: str = None):
|
138
159
|
uuids = self.uuids()
|
@@ -149,7 +170,7 @@ class Log():
|
|
149
170
|
def collapse(self, events: List[LogEvent]) -> List[LogEvent]:
|
150
171
|
events_count = {}
|
151
172
|
|
152
|
-
# More recent events take precedence over earlier ones,
|
173
|
+
# More recent events take precedence over earlier ones, only the most recent event
|
153
174
|
for event in events:
|
154
175
|
event_key = event.key
|
155
176
|
|
@@ -197,12 +218,18 @@ class Log():
|
|
197
218
|
|
198
219
|
resource_index[event.resource_uuid].append(event)
|
199
220
|
|
221
|
+
scenario_inverted_index = self.scenario_inverted_index
|
222
|
+
|
200
223
|
pruned_events = self.collapse(events)
|
201
224
|
for event in pruned_events:
|
202
225
|
snapshot = event.snapshot()
|
203
226
|
snapshot_exists = snapshot.exists
|
204
227
|
|
205
228
|
if event.action == DELETE_ACTION or not snapshot_exists:
|
229
|
+
if event.is_request() and event.resource_uuid in scenario_inverted_index:
|
230
|
+
# If a request is deleted, only prune if it's not also a part of a scenario
|
231
|
+
continue
|
232
|
+
|
206
233
|
Logger.instance(LOG_ID).info(f"{bcolors.OKBLUE}Removing{bcolors.ENDC} {event.resource} {event.resource_uuid}")
|
207
234
|
|
208
235
|
resource_events: List[LogEvent] = resource_index[event.resource_uuid]
|
@@ -218,8 +245,16 @@ class Log():
|
|
218
245
|
removed_events[event.uuid] = True
|
219
246
|
|
220
247
|
if event.action == DELETE_ACTION and snapshot_exists:
|
221
|
-
if
|
248
|
+
if dry_run:
|
249
|
+
continue
|
250
|
+
|
251
|
+
if event.is_scenario():
|
252
|
+
# We still need to check each request in a scenario to make sure another scenario does not depend on it
|
253
|
+
snapshot.remove(lambda snapshot: self.remove_request_snapshot(snapshot, scenario_inverted_index))
|
254
|
+
elif event.is_request():
|
255
|
+
# We have already checked that a scenario does not depend on the request above
|
222
256
|
snapshot.remove()
|
257
|
+
|
223
258
|
Logger.instance(LOG_ID).info(f"Removing {event.resource} snapshot")
|
224
259
|
|
225
260
|
def build_raw_events(self, contents: str) -> List[str]:
|
@@ -240,8 +275,10 @@ class Log():
|
|
240
275
|
|
241
276
|
def remove_dangling_events(self, processed_events: List[LogEvent], unprocessed_events: List[LogEvent]):
|
242
277
|
'''
|
243
|
-
Remove DELETE events
|
278
|
+
Remove DELETE events unless the last processed event was a PUT
|
244
279
|
'''
|
280
|
+
|
281
|
+
# Build an index to keep track of the last action that occurred for a resource
|
245
282
|
index = {}
|
246
283
|
for event in processed_events:
|
247
284
|
if event.action == PUT_ACTION:
|
@@ -249,10 +286,32 @@ class Log():
|
|
249
286
|
elif event.action == DELETE_ACTION:
|
250
287
|
if event.resource_uuid in index:
|
251
288
|
del index[event.resource_uuid]
|
289
|
+
|
290
|
+
scenario_inverted_index = self.build_scenario_inverted_index(processed_events)
|
291
|
+
|
292
|
+
def keep(e: LogEvent):
|
293
|
+
# Keep the event if it's a PUT, it may have been updated
|
294
|
+
if e.action == PUT_ACTION:
|
295
|
+
return True
|
296
|
+
|
297
|
+
if e.action == DELETE_ACTION:
|
298
|
+
if e.is_request():
|
299
|
+
referenced = e.resource_uuid in scenario_inverted_index
|
300
|
+
# Keep the DELETE event if the requests exists in a scenario
|
301
|
+
# or if it doesn't exist in a scenario, there was a previous delete event
|
302
|
+
return referenced or (e.resource_uuid in index and not referenced)
|
303
|
+
elif e.is_scenario():
|
304
|
+
# Update scenario_inverted_index with unprocessed event
|
305
|
+
self.build_scenario_inverted_index([e], scenario_inverted_index)
|
306
|
+
|
307
|
+
# Keep DELETE scenario event only if previous event for the resource was PUT
|
308
|
+
return e.resource_uuid in index
|
309
|
+
else:
|
310
|
+
return True
|
252
311
|
|
253
312
|
return list(
|
254
313
|
filter(
|
255
|
-
|
314
|
+
keep,
|
256
315
|
unprocessed_events
|
257
316
|
)
|
258
317
|
)
|
@@ -289,6 +348,12 @@ class Log():
|
|
289
348
|
remaining_events = self.remove_dangling_events(processed_events, unprocessed_events)
|
290
349
|
return list(filter(lambda e: e.uuid not in remaining_version_uuids, remaining_events))
|
291
350
|
|
351
|
+
def remove_request_snapshot(self, snapshot: RequestSnapshot, scenario_inverted_index: dict = None):
|
352
|
+
scenario_inverted_index = scenario_inverted_index or self.scenario_inverted_index
|
353
|
+
|
354
|
+
if snapshot.uuid not in scenario_inverted_index:
|
355
|
+
snapshot.remove()
|
356
|
+
|
292
357
|
# Rotate log to history
|
293
358
|
def rotate(self):
|
294
359
|
if not os.path.exists(self.__log_file_path):
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
import os
|
3
3
|
import pdb
|
4
|
-
import shutil
|
5
4
|
|
6
5
|
from typing import Callable, List
|
7
6
|
|
@@ -128,12 +127,12 @@ class ScenarioSnapshot(Snapshot):
|
|
128
127
|
if os.path.exists(metadata_file_path):
|
129
128
|
os.remove(metadata_file_path)
|
130
129
|
|
131
|
-
def remove_requests(self):
|
130
|
+
def remove_requests(self, handle_remove_request_snapshot = None):
|
132
131
|
requests_file_path = self.requests_path
|
133
132
|
|
134
133
|
if os.path.exists(requests_file_path):
|
135
134
|
# A request only every belongs to one scenario
|
136
|
-
self.iter_request_snapshots(self.__handle_remove_requests)
|
135
|
+
self.iter_request_snapshots(handle_remove_request_snapshot or self.__handle_remove_requests)
|
137
136
|
|
138
137
|
os.remove(requests_file_path)
|
139
138
|
|
@@ -14,15 +14,17 @@ def snapshot_request(request: Request, **options: RequestSnapshotOptions):
|
|
14
14
|
return
|
15
15
|
|
16
16
|
snapshot = RequestSnapshot(request.uuid)
|
17
|
-
|
18
17
|
snapshot.backup()
|
19
18
|
|
19
|
+
log = Log()
|
20
|
+
|
20
21
|
if action == PUT_ACTION:
|
21
22
|
snapshot.write(request, **options)
|
22
23
|
elif action == DELETE_ACTION:
|
23
|
-
|
24
|
+
inverted_scenario_index = log.scenario_inverted_index
|
24
25
|
|
25
|
-
|
26
|
+
# If a scenario currently depends on this request, we can't remove the snapshot until the scenario is also removed
|
27
|
+
log.remove_request_snapshot(snapshot, inverted_scenario_index)
|
26
28
|
|
27
29
|
try:
|
28
30
|
if action == PUT_ACTION:
|
@@ -40,7 +42,6 @@ def snapshot_scenario(scenario: Scenario, **options):
|
|
40
42
|
return
|
41
43
|
|
42
44
|
snapshot = ScenarioSnapshot(scenario.uuid)
|
43
|
-
|
44
45
|
snapshot.backup_metadata()
|
45
46
|
|
46
47
|
if action == PUT_ACTION:
|
@@ -50,13 +51,13 @@ def snapshot_scenario(scenario: Scenario, **options):
|
|
50
51
|
|
51
52
|
snapshot.backup_requests()
|
52
53
|
|
54
|
+
log = Log()
|
55
|
+
inverted_scenario_index = log.scenario_inverted_index
|
53
56
|
if action == PUT_ACTION:
|
54
|
-
snapshot.remove_requests()
|
57
|
+
snapshot.remove_requests(lambda snapshot: log.remove_request_snapshot(snapshot, inverted_scenario_index))
|
55
58
|
snapshot.write_requests(scenario, **options)
|
56
59
|
elif action == DELETE_ACTION:
|
57
|
-
snapshot.remove_requests()
|
58
|
-
|
59
|
-
log = Log()
|
60
|
+
snapshot.remove_requests(lambda snapshot: log.remove_request_snapshot(snapshot, inverted_scenario_index))
|
60
61
|
|
61
62
|
if action == PUT_ACTION:
|
62
63
|
log.put(scenario)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
import pdb
|
2
2
|
|
3
|
+
from typing import List
|
4
|
+
|
3
5
|
from stoobly_agent.app.models.factories.resource.local_db.helpers.log import Log
|
4
6
|
from stoobly_agent.app.models.factories.resource.local_db.helpers.request_snapshot import RequestSnapshot
|
5
7
|
from stoobly_agent.app.models.factories.resource.local_db.helpers.scenario_snapshot import ScenarioSnapshot
|
@@ -71,6 +73,7 @@ class Apply():
|
|
71
73
|
if results:
|
72
74
|
status = results[1]
|
73
75
|
if status == 0 or status >= 400:
|
76
|
+
self.__logger(f"{bcolors.FAIL}Error{bcolors.ENDC} {results[0]}")
|
74
77
|
completed = False
|
75
78
|
break
|
76
79
|
|
@@ -218,14 +221,16 @@ class Apply():
|
|
218
221
|
|
219
222
|
snapshot_requests = {}
|
220
223
|
|
221
|
-
request_snapshots = snapshot.request_snapshots
|
224
|
+
request_snapshots: List[RequestSnapshot] = snapshot.request_snapshots
|
222
225
|
for request_snapshot in request_snapshots:
|
223
226
|
raw_request = request_snapshot.request
|
224
|
-
|
225
|
-
toks = raw_request.split(REQUEST_STRING_CLRF, 1)
|
226
227
|
|
228
|
+
if not raw_request:
|
229
|
+
return f"{request_snapshot.path} is missing", 400
|
230
|
+
|
231
|
+
toks = raw_request.split(REQUEST_STRING_CLRF, 1)
|
227
232
|
if len(toks) != 2:
|
228
|
-
return f"{
|
233
|
+
return f"{request_snapshot.path} contains an invalid request", 400
|
229
234
|
|
230
235
|
uuid = request_snapshot.uuid
|
231
236
|
res, status = self.__put_request(uuid, raw_request, scenario_id=scenario['id'])
|
@@ -147,15 +147,8 @@ def handle_request_mock(context: MockContext):
|
|
147
147
|
# 2. AFTER_MOCK gets triggered (if mock found)
|
148
148
|
#
|
149
149
|
def handle_response_mock(context: MockContext):
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
if request_key:
|
154
|
-
request = context.flow.request
|
155
|
-
Logger.instance(LOG_ID).info(f"{bcolors.OKBLUE}Mocked{bcolors.ENDC} {request.url} -> {request_key}")
|
156
|
-
|
157
|
-
__rewrite_response(context)
|
158
|
-
__mock_hook(lifecycle_hooks.AFTER_MOCK, context)
|
150
|
+
__rewrite_response(context)
|
151
|
+
__mock_hook(lifecycle_hooks.AFTER_MOCK, context)
|
159
152
|
|
160
153
|
def __handle_mock_failure(context: MockContext) -> None:
|
161
154
|
flow = context.flow
|
@@ -186,6 +179,19 @@ def __handle_found_policy(context: MockContext) -> None:
|
|
186
179
|
reverse_proxy(req, upstream_url, {})
|
187
180
|
|
188
181
|
def __handle_mock_success(context: MockContext) -> None:
|
182
|
+
response = context.response
|
183
|
+
|
184
|
+
if response:
|
185
|
+
request = context.flow.request
|
186
|
+
|
187
|
+
request_key = response.headers.get(custom_headers.MOCK_REQUEST_KEY)
|
188
|
+
if request_key:
|
189
|
+
Logger.instance(LOG_ID).info(f"{bcolors.OKBLUE}Mocked{bcolors.ENDC} {request.url} -> {request_key}")
|
190
|
+
|
191
|
+
fixture_path = response.headers.get(custom_headers.MOCK_FIXTURE_PATH)
|
192
|
+
if fixture_path:
|
193
|
+
Logger.instance(LOG_ID).info(f"{bcolors.OKBLUE}Mocked{bcolors.ENDC} {request.url} -> {fixture_path}")
|
194
|
+
|
189
195
|
if os.environ.get(env_vars.AGENT_SIMULATE_LATENCY):
|
190
196
|
response = context.response
|
191
197
|
start_time = context.start_time
|
@@ -10,6 +10,7 @@ from requests.structures import CaseInsensitiveDict
|
|
10
10
|
from typing import Union
|
11
11
|
|
12
12
|
from stoobly_agent.lib.logger import bcolors, Logger
|
13
|
+
from stoobly_agent.config.constants.custom_headers import MOCK_FIXTURE_PATH
|
13
14
|
|
14
15
|
from .types import Fixtures
|
15
16
|
|
@@ -20,45 +21,50 @@ class Options():
|
|
20
21
|
response_fixtures: Fixtures
|
21
22
|
|
22
23
|
def eval_fixtures(request: MitmproxyRequest, **options: Options) -> Union[Response, None]:
|
23
|
-
fixture_path =
|
24
|
+
fixture_path = request.headers.get(MOCK_FIXTURE_PATH)
|
24
25
|
headers = CaseInsensitiveDict()
|
25
26
|
status_code = 200
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if not fixture:
|
31
|
-
public_directory_path = options.get('public_directory_path')
|
32
|
-
|
33
|
-
if not public_directory_path:
|
28
|
+
if fixture_path:
|
29
|
+
if not os.path.exists(fixture_path):
|
34
30
|
return
|
31
|
+
else:
|
32
|
+
response_fixtures = options.get('response_fixtures')
|
33
|
+
fixture: dict = __eval_response_fixtures(request, response_fixtures)
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
if request.headers.get('accept'):
|
39
|
-
fixture_path = __guess_file_path(_fixture_path, request.headers['accept'])
|
35
|
+
if not fixture:
|
36
|
+
public_directory_path = options.get('public_directory_path')
|
40
37
|
|
41
|
-
|
42
|
-
|
38
|
+
if not public_directory_path:
|
39
|
+
return
|
43
40
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
41
|
+
request_path = 'index' if request.path == '/' else request.path
|
42
|
+
_fixture_path = os.path.join(public_directory_path, request_path.lstrip('/'))
|
43
|
+
if request.headers.get('accept'):
|
44
|
+
fixture_path = __guess_file_path(_fixture_path, request.headers['accept'])
|
45
|
+
|
46
|
+
if not fixture_path:
|
47
|
+
fixture_path = _fixture_path
|
50
48
|
|
51
|
-
|
52
|
-
|
49
|
+
if not os.path.isfile(fixture_path):
|
50
|
+
return
|
51
|
+
else:
|
52
|
+
fixture_path = fixture.get('path')
|
53
|
+
if not fixture_path or not os.path.isfile(fixture_path):
|
54
|
+
return
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
+
_headers = fixture.get('headers')
|
57
|
+
headers = CaseInsensitiveDict(_headers if isinstance(_headers, dict) else {})
|
56
58
|
|
59
|
+
if fixture.get('status_code'):
|
60
|
+
status_code = fixture.get('status_code')
|
61
|
+
|
57
62
|
with open(fixture_path, 'rb') as fp:
|
58
63
|
response = Response()
|
59
64
|
|
60
65
|
response.status_code = status_code
|
61
66
|
response.raw = BytesIO(fp.read())
|
67
|
+
headers[MOCK_FIXTURE_PATH] = fixture_path
|
62
68
|
response.headers = headers
|
63
69
|
|
64
70
|
if not response.headers.get('content-type'):
|
@@ -2,6 +2,7 @@ ALIAS_RESOLVE_STRATEGY = 'X-Stoobly-Alias-Resolve-Strategy'
|
|
2
2
|
CONTENT_TYPE = 'X-Stoobly-Content-Type'
|
3
3
|
CONTENT_TYPE_TEST_RESULTS = 'test/results'
|
4
4
|
REMOTE_PROJECT_KEY = 'X-Stoobly-Endpoints-Project-Id'
|
5
|
+
MOCK_FIXTURE_PATH = 'X-Stoobly-Fixture-Path'
|
5
6
|
MOCK_POLICY = 'X-Stoobly-Mock-Policy'
|
6
7
|
MOCK_REQUEST_ID = 'X-Stoobly-Request-Id'
|
7
8
|
MOCK_REQUEST_ENDPOINT_ID = 'X-Stoobly-Request-Endpoint-Id'
|
@@ -1,16 +1,18 @@
|
|
1
1
|
import pdb
|
2
2
|
import pytest
|
3
|
+
import time
|
3
4
|
|
4
5
|
from click.testing import CliRunner
|
5
|
-
|
6
|
-
from stoobly_agent.test.test_helper import DETERMINISTIC_GET_REQUEST_URL, reset
|
6
|
+
from typing import List
|
7
7
|
|
8
8
|
from stoobly_agent.app.models.adapters.orm import JoinedRequestStringAdapter
|
9
9
|
from stoobly_agent.app.models.factories.resource.local_db.helpers.log import Log
|
10
|
-
from stoobly_agent.app.models.factories.resource.local_db.helpers.log_event import DELETE_ACTION
|
10
|
+
from stoobly_agent.app.models.factories.resource.local_db.helpers.log_event import DELETE_ACTION, PUT_ACTION
|
11
11
|
from stoobly_agent.app.models.factories.resource.local_db.helpers.request_snapshot import RequestSnapshot
|
12
|
-
from stoobly_agent.cli import record, request
|
12
|
+
from stoobly_agent.cli import record, request, scenario, snapshot
|
13
13
|
from stoobly_agent.lib.orm.request import Request
|
14
|
+
from stoobly_agent.lib.orm.scenario import Scenario
|
15
|
+
from stoobly_agent.test.test_helper import DETERMINISTIC_GET_REQUEST_URL, NON_DETERMINISTIC_GET_REQUEST_URL, reset
|
14
16
|
|
15
17
|
@pytest.fixture(scope='module')
|
16
18
|
def runner():
|
@@ -122,3 +124,51 @@ class TestRequestSnapshot():
|
|
122
124
|
|
123
125
|
event = unprocessed_events[0]
|
124
126
|
assert event.resource_uuid == recorded_request_two.uuid
|
127
|
+
assert event.action == PUT_ACTION
|
128
|
+
|
129
|
+
class TestWhenDeleteFirst():
|
130
|
+
|
131
|
+
@pytest.fixture(scope='class')
|
132
|
+
def recorded_request(self, runner: CliRunner):
|
133
|
+
record_result = runner.invoke(record, [DETERMINISTIC_GET_REQUEST_URL])
|
134
|
+
assert record_result.exit_code == 0
|
135
|
+
return Request.last()
|
136
|
+
|
137
|
+
def test_initial_delete(self, runner: CliRunner, recorded_request: Request):
|
138
|
+
snapshot_result = runner.invoke(request, ['snapshot', '--action', DELETE_ACTION, recorded_request.key()])
|
139
|
+
assert snapshot_result.exit_code == 0
|
140
|
+
|
141
|
+
log = Log()
|
142
|
+
|
143
|
+
events = log.raw_events
|
144
|
+
assert len(events) == 1
|
145
|
+
|
146
|
+
unprocessed_events = log.unprocessed_events
|
147
|
+
assert len(unprocessed_events) == 0
|
148
|
+
|
149
|
+
def test_puts(self, runner: CliRunner, recorded_request: Request):
|
150
|
+
snapshot_result = runner.invoke(request, ['snapshot', '--action', PUT_ACTION, recorded_request.key()])
|
151
|
+
assert snapshot_result.exit_code == 0
|
152
|
+
|
153
|
+
log = Log()
|
154
|
+
|
155
|
+
events = log.raw_events
|
156
|
+
assert len(events) == 2
|
157
|
+
|
158
|
+
unprocessed_events = log.unprocessed_events
|
159
|
+
assert len(unprocessed_events) == 1
|
160
|
+
assert unprocessed_events[0].action == PUT_ACTION
|
161
|
+
|
162
|
+
def test_final_delete(self, runner: CliRunner, recorded_request: Request):
|
163
|
+
snapshot_result = runner.invoke(request, ['snapshot', '--action', DELETE_ACTION, recorded_request.key()])
|
164
|
+
assert snapshot_result.exit_code == 0
|
165
|
+
|
166
|
+
log = Log()
|
167
|
+
|
168
|
+
events = log.events
|
169
|
+
assert len(events) == 3
|
170
|
+
|
171
|
+
collapsed_events = log.collapse(events)
|
172
|
+
assert len(collapsed_events) == 1
|
173
|
+
unprocessed_events = log.unprocessed_events
|
174
|
+
assert len(unprocessed_events) == 0
|
@@ -547,4 +547,266 @@ class TestApply():
|
|
547
547
|
recreated_scenario = Scenario.find_by(uuid=created_scenario.uuid)
|
548
548
|
assert recreated_scenario
|
549
549
|
|
550
|
-
assert len(recreated_scenario.requests) == 0
|
550
|
+
assert len(recreated_scenario.requests) == 0
|
551
|
+
|
552
|
+
class TestWhenDeletingRequestWhileReferenced():
|
553
|
+
|
554
|
+
class TestWhenRemoveScenarioRequest():
|
555
|
+
'''
|
556
|
+
1. Create scenario
|
557
|
+
2. Add 2 requests to it
|
558
|
+
3. Snapshot scenario
|
559
|
+
4. Snapshot second request with action DELETE_ACTION
|
560
|
+
5. Apply
|
561
|
+
6. Expect scenario to have 1 request
|
562
|
+
'''
|
563
|
+
|
564
|
+
@pytest.fixture(scope='class')
|
565
|
+
def created_scenario(self, runner: CliRunner):
|
566
|
+
create_result = runner.invoke(scenario, ['create', 'test'])
|
567
|
+
assert create_result.exit_code == 0
|
568
|
+
return Scenario.last()
|
569
|
+
|
570
|
+
@pytest.fixture(scope='class', autouse=True)
|
571
|
+
def created_scenario_requests(self, runner: CliRunner, created_scenario: Scenario):
|
572
|
+
record_result = runner.invoke(record, ['--scenario-key', created_scenario.key(), DETERMINISTIC_GET_REQUEST_URL])
|
573
|
+
assert record_result.exit_code == 0
|
574
|
+
|
575
|
+
record_result = runner.invoke(record, ['--scenario-key', created_scenario.key(), NON_DETERMINISTIC_GET_REQUEST_URL])
|
576
|
+
assert record_result.exit_code == 0
|
577
|
+
|
578
|
+
return created_scenario.requests
|
579
|
+
|
580
|
+
@pytest.fixture(scope='class', autouse=True)
|
581
|
+
def delete_event(self, runner: CliRunner, created_scenario: Scenario, created_scenario_requests: List[Request]):
|
582
|
+
snapshot_result = runner.invoke(scenario, ['snapshot', created_scenario.key()])
|
583
|
+
assert snapshot_result.exit_code == 0
|
584
|
+
|
585
|
+
time.sleep(0.5) # So events do not have the same uuid
|
586
|
+
|
587
|
+
created_request = created_scenario_requests[1]
|
588
|
+
snapshot_result = runner.invoke(request, ['snapshot', created_request.key(), '--action', DELETE_ACTION])
|
589
|
+
assert snapshot_result.exit_code == 0
|
590
|
+
|
591
|
+
log = Log()
|
592
|
+
events = log.events
|
593
|
+
return events[len(events) - 1]
|
594
|
+
|
595
|
+
@pytest.fixture(scope='class')
|
596
|
+
def apply_result(self, runner: CliRunner, created_scenario: Scenario):
|
597
|
+
created_scenario = Scenario.find(created_scenario.id)
|
598
|
+
assert created_scenario.requests_count == 2
|
599
|
+
apply_result = runner.invoke(snapshot, ['apply'])
|
600
|
+
|
601
|
+
return apply_result
|
602
|
+
|
603
|
+
def test_it_updates_scenario(self, created_scenario: Scenario, apply_result):
|
604
|
+
assert apply_result.exit_code == 0
|
605
|
+
|
606
|
+
created_scenario = Scenario.find(created_scenario.id)
|
607
|
+
assert created_scenario.requests_count == 1
|
608
|
+
|
609
|
+
def test_it_maintains_requests(self, created_scenario: Scenario, created_scenario_requests: List[Request]):
|
610
|
+
created_scenario = Scenario.find(created_scenario.id)
|
611
|
+
assert len(created_scenario.requests) == 1
|
612
|
+
|
613
|
+
requests = created_scenario.requests
|
614
|
+
|
615
|
+
assert_orm_request_equivalent(requests[0], created_scenario_requests[0])
|
616
|
+
|
617
|
+
class TestWhenMovingScenarioRequest():
|
618
|
+
'''
|
619
|
+
1. Create scenario one and scenario two
|
620
|
+
2. Add 1 request to scenario one
|
621
|
+
3. Snapshot scenario one
|
622
|
+
4. Move scenario one request to scenario two
|
623
|
+
5. Snapshot scenario two
|
624
|
+
5. Apply
|
625
|
+
6. Expect scenario one to have 0 requests
|
626
|
+
7. Expect scenario two to have 1 request
|
627
|
+
'''
|
628
|
+
|
629
|
+
@pytest.fixture(scope='class')
|
630
|
+
def created_scenario_one(self, runner: CliRunner):
|
631
|
+
create_result = runner.invoke(scenario, ['create', 'test1'])
|
632
|
+
assert create_result.exit_code == 0
|
633
|
+
return Scenario.last()
|
634
|
+
|
635
|
+
@pytest.fixture(scope='class')
|
636
|
+
def created_scenario_two(self, runner: CliRunner):
|
637
|
+
create_result = runner.invoke(scenario, ['create', 'test2'])
|
638
|
+
assert create_result.exit_code == 0
|
639
|
+
return Scenario.last()
|
640
|
+
|
641
|
+
@pytest.fixture(scope='class', autouse=True)
|
642
|
+
def created_scenario_request(self, runner: CliRunner, created_scenario_one: Scenario):
|
643
|
+
record_result = runner.invoke(record, ['--scenario-key', created_scenario_one.key(), DETERMINISTIC_GET_REQUEST_URL])
|
644
|
+
assert record_result.exit_code == 0
|
645
|
+
|
646
|
+
return created_scenario_one.requests[0]
|
647
|
+
|
648
|
+
@pytest.fixture(scope='class', autouse=True)
|
649
|
+
def put_event_one(self, runner: CliRunner, created_scenario_one: Scenario, created_scenario_request: Request):
|
650
|
+
snapshot_result = runner.invoke(scenario, ['snapshot', created_scenario_one.key()])
|
651
|
+
assert snapshot_result.exit_code == 0
|
652
|
+
|
653
|
+
log = Log()
|
654
|
+
events = log.events
|
655
|
+
return events[len(events) - 1]
|
656
|
+
|
657
|
+
@pytest.fixture(scope='class', autouse=True)
|
658
|
+
def put_event_two(self, runner: CliRunner, created_scenario_two: Scenario, created_scenario_request: Request):
|
659
|
+
created_scenario_request.update(scenario_id=created_scenario_two.id)
|
660
|
+
|
661
|
+
snapshot_result = runner.invoke(scenario, ['snapshot', created_scenario_two.key()])
|
662
|
+
assert snapshot_result.exit_code == 0
|
663
|
+
|
664
|
+
log = Log()
|
665
|
+
events = log.events
|
666
|
+
return events[len(events) - 1]
|
667
|
+
|
668
|
+
@pytest.fixture(scope='class')
|
669
|
+
def apply_result(self, runner: CliRunner):
|
670
|
+
apply_result = runner.invoke(snapshot, ['apply'])
|
671
|
+
|
672
|
+
return apply_result
|
673
|
+
|
674
|
+
def test_it_removes_request_from_scenario_one(self, created_scenario_one: Scenario, apply_result):
|
675
|
+
assert apply_result.exit_code == 0
|
676
|
+
|
677
|
+
created_scenario_one = Scenario.find(created_scenario_one.id)
|
678
|
+
assert created_scenario_one.requests_count == 0
|
679
|
+
|
680
|
+
def test_it_adds_request_to_scenario_two(self, created_scenario_two: Scenario, apply_result):
|
681
|
+
assert apply_result.exit_code == 0
|
682
|
+
|
683
|
+
created_scenario_two = Scenario.find(created_scenario_two.id)
|
684
|
+
assert created_scenario_two.requests_count == 1
|
685
|
+
|
686
|
+
def test_it_maintains_requests(self, created_scenario_two: Scenario, created_scenario_request):
|
687
|
+
created_scenario_two = Scenario.find(created_scenario_two.id)
|
688
|
+
assert len(created_scenario_two.requests) == 1
|
689
|
+
|
690
|
+
requests = created_scenario_two.requests
|
691
|
+
|
692
|
+
assert_orm_request_equivalent(requests[0], created_scenario_request)
|
693
|
+
|
694
|
+
class TestApply():
|
695
|
+
|
696
|
+
class TestWhenNoApply():
|
697
|
+
'''
|
698
|
+
1. Create scenario
|
699
|
+
2. Add 2 requests to it
|
700
|
+
3. Snapshot scenario
|
701
|
+
4. Apply scenario
|
702
|
+
5. Snapshot second request with action DELETE_ACTION
|
703
|
+
6. Prune
|
704
|
+
7. Apply
|
705
|
+
8. Expect scenario to have 1 request, because scenario depends on the request, should not be able to prune
|
706
|
+
'''
|
707
|
+
|
708
|
+
@pytest.fixture(scope='class')
|
709
|
+
def created_scenario(self, runner: CliRunner):
|
710
|
+
create_result = runner.invoke(scenario, ['create', 'test'])
|
711
|
+
assert create_result.exit_code == 0
|
712
|
+
return Scenario.last()
|
713
|
+
|
714
|
+
@pytest.fixture(scope='class', autouse=True)
|
715
|
+
def created_scenario_requests(self, runner: CliRunner, created_scenario: Scenario):
|
716
|
+
record_result = runner.invoke(record, ['--scenario-key', created_scenario.key(), DETERMINISTIC_GET_REQUEST_URL])
|
717
|
+
assert record_result.exit_code == 0
|
718
|
+
|
719
|
+
record_result = runner.invoke(record, ['--scenario-key', created_scenario.key(), NON_DETERMINISTIC_GET_REQUEST_URL])
|
720
|
+
assert record_result.exit_code == 0
|
721
|
+
|
722
|
+
return created_scenario.requests
|
723
|
+
|
724
|
+
@pytest.fixture(scope='class', autouse=True)
|
725
|
+
def snapshots(self, runner: CliRunner, created_scenario: Scenario, created_scenario_requests: List[Request]):
|
726
|
+
snapshot_result = runner.invoke(scenario, ['snapshot', created_scenario.key()])
|
727
|
+
assert snapshot_result.exit_code == 0
|
728
|
+
|
729
|
+
created_request = created_scenario_requests[1]
|
730
|
+
snapshot_result = runner.invoke(request, ['snapshot', created_request.key(), '--action', DELETE_ACTION])
|
731
|
+
assert snapshot_result.exit_code == 0
|
732
|
+
|
733
|
+
def test_events(self):
|
734
|
+
log = Log()
|
735
|
+
|
736
|
+
events = log.events
|
737
|
+
assert len(events) == 2
|
738
|
+
|
739
|
+
def test_collapsed_events(self):
|
740
|
+
log = Log()
|
741
|
+
|
742
|
+
collapsed_events = log.collapse(log.events)
|
743
|
+
assert len(collapsed_events) == 2
|
744
|
+
|
745
|
+
def test_unprocessed_events(self):
|
746
|
+
log = Log()
|
747
|
+
|
748
|
+
unprocessed_events = log.unprocessed_events
|
749
|
+
assert len(unprocessed_events) == 2
|
750
|
+
|
751
|
+
class TestWhenRemoveScenarioRequest():
|
752
|
+
'''
|
753
|
+
1. Create scenario
|
754
|
+
2. Add 2 requests to it
|
755
|
+
3. Snapshot scenario
|
756
|
+
4. Apply scenario
|
757
|
+
5. Snapshot second request with action DELETE_ACTION
|
758
|
+
6. Prune
|
759
|
+
7. Apply
|
760
|
+
8. Expect scenario to have 1 request, because scenario depends on the request, should not be able to prune
|
761
|
+
'''
|
762
|
+
|
763
|
+
@pytest.fixture(scope='class')
|
764
|
+
def created_scenario(self, runner: CliRunner):
|
765
|
+
create_result = runner.invoke(scenario, ['create', 'test'])
|
766
|
+
assert create_result.exit_code == 0
|
767
|
+
return Scenario.last()
|
768
|
+
|
769
|
+
@pytest.fixture(scope='class', autouse=True)
|
770
|
+
def created_scenario_requests(self, runner: CliRunner, created_scenario: Scenario):
|
771
|
+
record_result = runner.invoke(record, ['--scenario-key', created_scenario.key(), DETERMINISTIC_GET_REQUEST_URL])
|
772
|
+
assert record_result.exit_code == 0
|
773
|
+
|
774
|
+
record_result = runner.invoke(record, ['--scenario-key', created_scenario.key(), NON_DETERMINISTIC_GET_REQUEST_URL])
|
775
|
+
assert record_result.exit_code == 0
|
776
|
+
|
777
|
+
return created_scenario.requests
|
778
|
+
|
779
|
+
@pytest.fixture(scope='class', autouse=True)
|
780
|
+
def apply_result(self, runner: CliRunner, created_scenario: Scenario, created_scenario_requests: List[Request]):
|
781
|
+
snapshot_result = runner.invoke(scenario, ['snapshot', created_scenario.key()])
|
782
|
+
assert snapshot_result.exit_code == 0
|
783
|
+
|
784
|
+
created_scenario = Scenario.find(created_scenario.id)
|
785
|
+
assert created_scenario.requests_count == 2
|
786
|
+
apply_result = runner.invoke(snapshot, ['apply'])
|
787
|
+
assert apply_result.exit_code == 0
|
788
|
+
|
789
|
+
created_request = created_scenario_requests[1]
|
790
|
+
snapshot_result = runner.invoke(request, ['snapshot', created_request.key(), '--action', DELETE_ACTION])
|
791
|
+
assert snapshot_result.exit_code == 0
|
792
|
+
|
793
|
+
return apply_result
|
794
|
+
|
795
|
+
def test_events(self):
|
796
|
+
log = Log()
|
797
|
+
|
798
|
+
events = log.events
|
799
|
+
assert len(events) == 2
|
800
|
+
|
801
|
+
def test_collapsed_events(self):
|
802
|
+
log = Log()
|
803
|
+
|
804
|
+
collapsed_events = log.collapse(log.events)
|
805
|
+
assert len(collapsed_events) == 2
|
806
|
+
|
807
|
+
def test_unprocessed_events(self):
|
808
|
+
log = Log()
|
809
|
+
|
810
|
+
unprocessed_events = log.unprocessed_events
|
811
|
+
assert len(unprocessed_events) == 1
|
812
|
+
assert unprocessed_events[0].action == DELETE_ACTION
|
@@ -3,12 +3,14 @@ import pytest
|
|
3
3
|
import time
|
4
4
|
|
5
5
|
from click.testing import CliRunner
|
6
|
+
from typing import List
|
6
7
|
|
7
8
|
from stoobly_agent.app.models.factories.resource.local_db.helpers.log import Log
|
8
9
|
from stoobly_agent.app.models.factories.resource.local_db.helpers.log_event import DELETE_ACTION, LogEvent
|
9
|
-
from stoobly_agent.cli import record, request, snapshot
|
10
|
+
from stoobly_agent.cli import record, request, scenario, snapshot
|
10
11
|
from stoobly_agent.lib.orm.request import Request
|
11
|
-
from stoobly_agent.
|
12
|
+
from stoobly_agent.lib.orm.scenario import Scenario
|
13
|
+
from stoobly_agent.test.test_helper import assert_orm_request_equivalent, DETERMINISTIC_GET_REQUEST_URL, NON_DETERMINISTIC_GET_REQUEST_URL, reset
|
12
14
|
|
13
15
|
@pytest.fixture(scope='module')
|
14
16
|
def runner():
|
@@ -107,4 +109,71 @@ class TestPrune():
|
|
107
109
|
|
108
110
|
apply_result = runner.invoke(snapshot, ['prune'])
|
109
111
|
assert apply_result.exit_code == 0
|
110
|
-
assert len(log.events) == 0
|
112
|
+
assert len(log.events) == 0
|
113
|
+
|
114
|
+
class TestWhenRemoveScenarioRequest():
|
115
|
+
'''
|
116
|
+
1. Create scenario
|
117
|
+
2. Add 2 requests to it
|
118
|
+
3. Snapshot scenario
|
119
|
+
4. Snapshot second request with action DELETE_ACTION
|
120
|
+
5. Prune
|
121
|
+
6. Apply
|
122
|
+
7. Expect scenario to have 1 request, because scenario depends on the request, should not be able to prune
|
123
|
+
'''
|
124
|
+
|
125
|
+
@pytest.fixture(scope='class')
|
126
|
+
def created_scenario(self, runner: CliRunner):
|
127
|
+
create_result = runner.invoke(scenario, ['create', 'test'])
|
128
|
+
assert create_result.exit_code == 0
|
129
|
+
return Scenario.last()
|
130
|
+
|
131
|
+
@pytest.fixture(scope='class', autouse=True)
|
132
|
+
def created_scenario_requests(self, runner: CliRunner, created_scenario: Scenario):
|
133
|
+
record_result = runner.invoke(record, ['--scenario-key', created_scenario.key(), DETERMINISTIC_GET_REQUEST_URL])
|
134
|
+
assert record_result.exit_code == 0
|
135
|
+
|
136
|
+
record_result = runner.invoke(record, ['--scenario-key', created_scenario.key(), NON_DETERMINISTIC_GET_REQUEST_URL])
|
137
|
+
assert record_result.exit_code == 0
|
138
|
+
|
139
|
+
return created_scenario.requests
|
140
|
+
|
141
|
+
@pytest.fixture(scope='class', autouse=True)
|
142
|
+
def delete_event(self, runner: CliRunner, created_scenario: Scenario, created_scenario_requests: List[Request]):
|
143
|
+
snapshot_result = runner.invoke(scenario, ['snapshot', created_scenario.key()])
|
144
|
+
assert snapshot_result.exit_code == 0
|
145
|
+
|
146
|
+
time.sleep(0.5) # So events do not have the same uuid
|
147
|
+
|
148
|
+
created_request = created_scenario_requests[1]
|
149
|
+
snapshot_result = runner.invoke(request, ['snapshot', created_request.key(), '--action', DELETE_ACTION])
|
150
|
+
assert snapshot_result.exit_code == 0
|
151
|
+
|
152
|
+
log = Log()
|
153
|
+
events = log.events
|
154
|
+
return events[len(events) - 1]
|
155
|
+
|
156
|
+
@pytest.fixture(scope='class')
|
157
|
+
def apply_result(self, runner: CliRunner, created_scenario: Scenario):
|
158
|
+
prune_result = runner.invoke(snapshot, ['prune'])
|
159
|
+
assert prune_result.exit_code == 0
|
160
|
+
|
161
|
+
created_scenario = Scenario.find(created_scenario.id)
|
162
|
+
assert created_scenario.requests_count == 2
|
163
|
+
apply_result = runner.invoke(snapshot, ['apply'])
|
164
|
+
|
165
|
+
return apply_result
|
166
|
+
|
167
|
+
def test_it_updates_scenario(self, created_scenario: Scenario, apply_result):
|
168
|
+
assert apply_result.exit_code == 0
|
169
|
+
|
170
|
+
created_scenario = Scenario.find(created_scenario.id)
|
171
|
+
assert created_scenario.requests_count == 1
|
172
|
+
|
173
|
+
def test_it_maintains_requests(self, created_scenario: Scenario, created_scenario_requests: List[Request]):
|
174
|
+
created_scenario = Scenario.find(created_scenario.id)
|
175
|
+
assert len(created_scenario.requests) == 1
|
176
|
+
|
177
|
+
requests = created_scenario.requests
|
178
|
+
|
179
|
+
assert_orm_request_equivalent(requests[0], created_scenario_requests[0])
|
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.9.0
|
@@ -1,4 +1,4 @@
|
|
1
|
-
stoobly_agent/__init__.py,sha256=
|
1
|
+
stoobly_agent/__init__.py,sha256=epZElDe2ihHM7JdgjopRIH49aMQpYH4SYIjmxXXMnY0,44
|
2
2
|
stoobly_agent/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
stoobly_agent/app/api/__init__.py,sha256=ctkB8KR-eXO0SFhj602huHiyvQ3PslFWd8fkcufgrAI,1000
|
4
4
|
stoobly_agent/app/api/application_http_request_handler.py,sha256=Vvz53yB0bR7J-QqMAkLlhcZrA4P64ZEN7w8cMbgl6o0,5261
|
@@ -258,14 +258,14 @@ stoobly_agent/app/models/factories/resource/local_db/body_adapter.py,sha256=lrnI
|
|
258
258
|
stoobly_agent/app/models/factories/resource/local_db/header_adapter.py,sha256=NQdCErFtJL7sBaLpKLYfJSEA3AiaaVuU7LUcGJ-dHOI,3104
|
259
259
|
stoobly_agent/app/models/factories/resource/local_db/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
260
260
|
stoobly_agent/app/models/factories/resource/local_db/helpers/create_request_columns_service.py,sha256=HABMelW-cvhm2WXaywbQcd4PQhzSrz4vAbN7uOdetXM,1541
|
261
|
-
stoobly_agent/app/models/factories/resource/local_db/helpers/log.py,sha256=
|
261
|
+
stoobly_agent/app/models/factories/resource/local_db/helpers/log.py,sha256=COKyrRFZgxQgLVH6cs_Mvc616BScoldamg8QqG8JV3c,11670
|
262
262
|
stoobly_agent/app/models/factories/resource/local_db/helpers/log_event.py,sha256=30wWhqibTWgnpibosclaB9OCWzArL7R4krGS8WW2bGY,3584
|
263
263
|
stoobly_agent/app/models/factories/resource/local_db/helpers/request_builder.py,sha256=PyVvsYmi5bBQ6PsUPxQ4nJM9rhhjGVOTd7ipuc2tMMM,3227
|
264
|
-
stoobly_agent/app/models/factories/resource/local_db/helpers/request_snapshot.py,sha256=
|
265
|
-
stoobly_agent/app/models/factories/resource/local_db/helpers/scenario_snapshot.py,sha256=
|
264
|
+
stoobly_agent/app/models/factories/resource/local_db/helpers/request_snapshot.py,sha256=Tpuu7sZ4A2Vc5e5OAyU9pSKzbOpLpZoI-4E2Ty7n4Ac,2672
|
265
|
+
stoobly_agent/app/models/factories/resource/local_db/helpers/scenario_snapshot.py,sha256=f5psNwbl_mXF8rLNogqgfiHJudu2C9N9F35DZ_zgn6o,4973
|
266
266
|
stoobly_agent/app/models/factories/resource/local_db/helpers/search.py,sha256=A7KVcmxj9c3CT2rh26YH6khiEPkB_4U1UHhiYelNaws,782
|
267
267
|
stoobly_agent/app/models/factories/resource/local_db/helpers/snapshot.py,sha256=_8WPNE2NnvLlDbqnCfgnQveppDWfFZnqCBcX6THb1AU,742
|
268
|
-
stoobly_agent/app/models/factories/resource/local_db/helpers/snapshot_service.py,sha256=
|
268
|
+
stoobly_agent/app/models/factories/resource/local_db/helpers/snapshot_service.py,sha256=szL70Vubqg2JbxZ-rnlrxiqEgyPIcKAO9SsyyFxQ6ow,2106
|
269
269
|
stoobly_agent/app/models/factories/resource/local_db/helpers/snapshot_types.py,sha256=1pX0jrg13632g_yv_sF1ABzPR7LY7r2HC9g1a5zR1qI,379
|
270
270
|
stoobly_agent/app/models/factories/resource/local_db/helpers/tiebreak_scenario_request.py,sha256=BajElzsTE115hWBT6v67eyNFnrHGz-sU6WBNCzWp7Fg,1237
|
271
271
|
stoobly_agent/app/models/factories/resource/local_db/local_db_adapter.py,sha256=Zeem6abkSHXRXTvE3XwzOkUY6fbNm9wocPP2qSX3zQ8,1439
|
@@ -287,7 +287,7 @@ stoobly_agent/app/models/factories/resource/stoobly/request_adapter.py,sha256=Zr
|
|
287
287
|
stoobly_agent/app/models/factories/resource/stoobly/scenario_adapter.py,sha256=HnM4g5Qdv16QXj8u4JCiJm2Dbw9OhAxmn9e_R8oaHG4,1105
|
288
288
|
stoobly_agent/app/models/header_model.py,sha256=m91upRZr8GfE5um0d5dguUESKigBMWhSyu_X3HFk28Y,1406
|
289
289
|
stoobly_agent/app/models/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
290
|
-
stoobly_agent/app/models/helpers/apply.py,sha256=
|
290
|
+
stoobly_agent/app/models/helpers/apply.py,sha256=ev8QmDvV7flFo82JUA6kBkofYCJ_lNXQGVIpknB94g8,8501
|
291
291
|
stoobly_agent/app/models/helpers/create_request_params_service.py,sha256=o_VB2FsTGBX55UBBw1yQ8MtsJ4-0YXcxd4kNQ9l21nM,2070
|
292
292
|
stoobly_agent/app/models/model.py,sha256=77ZTByQmH5sWBcSrCF3kG_C4muHggcFyH1DWsOhIgvg,1180
|
293
293
|
stoobly_agent/app/models/query_param_model.py,sha256=EBj76phSJ9_45KgP0vIZGbkkG6-tSn_U1fNW_7qLy_4,1455
|
@@ -309,7 +309,7 @@ stoobly_agent/app/proxy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
|
|
309
309
|
stoobly_agent/app/proxy/constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
310
310
|
stoobly_agent/app/proxy/constants/custom_response_codes.py,sha256=1CaApt_6W7GrxvN8_Ozbf_SEodVEQaNZRR2sMYpI0U8,40
|
311
311
|
stoobly_agent/app/proxy/context.py,sha256=m6iu6QSZsim8meZS8H8DsZeXyjfoC-MRMHhQD1MFKM0,532
|
312
|
-
stoobly_agent/app/proxy/handle_mock_service.py,sha256=
|
312
|
+
stoobly_agent/app/proxy/handle_mock_service.py,sha256=qz7rxAg6R8U9aiXbYjuncDkx5eliPYX3x-uVLelwSr0,9451
|
313
313
|
stoobly_agent/app/proxy/handle_record_service.py,sha256=Fe8RAcMVvHhl3-XgjZ41242p4JXooYHQ-MhjcQhJn2E,4223
|
314
314
|
stoobly_agent/app/proxy/handle_replay_service.py,sha256=kBUYd8kj8UPrsYHoBXmq06DPLjCnHo8K-QsKzhDIKcw,2526
|
315
315
|
stoobly_agent/app/proxy/handle_test_service.py,sha256=WkMPbM4argVtl-TQB7VdQIvB8cOwURAahxFX5Vkqwws,8405
|
@@ -327,7 +327,7 @@ stoobly_agent/app/proxy/mitmproxy/response_facade.py,sha256=0wCSzUULUhDDV93QXUgz
|
|
327
327
|
stoobly_agent/app/proxy/mock/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
328
328
|
stoobly_agent/app/proxy/mock/context.py,sha256=vDo5_3WBL73mVFnsmQWvcxvPg5nWtRJbigSrE3zGc-o,794
|
329
329
|
stoobly_agent/app/proxy/mock/custom_not_found_response_builder.py,sha256=0KWB3KFxVrnJOKDaYxm5eoJEccw7IpJZRyUvBX61-8k,697
|
330
|
-
stoobly_agent/app/proxy/mock/eval_fixtures_service.py,sha256=
|
330
|
+
stoobly_agent/app/proxy/mock/eval_fixtures_service.py,sha256=sVw8l916ouEBj2ViDtHFjgmEA4tLmZGvBfw8wD1Ab-c,4132
|
331
331
|
stoobly_agent/app/proxy/mock/eval_request_service.py,sha256=A1tcE3wmrC1HwLpz0aRuRw-Nucn0dyHD_yHw5BeQEJU,8146
|
332
332
|
stoobly_agent/app/proxy/mock/hashed_request_decorator.py,sha256=h1ma90fdaYI9LBWpMWMqWBz-RjNwI628O4VuS_uUBX4,5061
|
333
333
|
stoobly_agent/app/proxy/mock/ignored_components_response_builder.py,sha256=E32_E1eSdmPn2SeM_e1jWnqu4xh5w_SnmOs32Shx99E,501
|
@@ -419,7 +419,7 @@ stoobly_agent/cli.py,sha256=sw8Ke5mCvzQ50X-zsb2Ld_zW4T6S58P0fN5GyKNOrcQ,10255
|
|
419
419
|
stoobly_agent/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
420
420
|
stoobly_agent/config/constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
421
421
|
stoobly_agent/config/constants/alias_resolve_strategy.py,sha256=_R1tVqFnyGxCraVS5-dhSskaDj_X8-NthsY7i_bEt9M,119
|
422
|
-
stoobly_agent/config/constants/custom_headers.py,sha256=
|
422
|
+
stoobly_agent/config/constants/custom_headers.py,sha256=8YiKDjrpe0qH8tr4qM_CgonBy6bf_HHTqQ7B_hYv2L0,1398
|
423
423
|
stoobly_agent/config/constants/env_vars.py,sha256=HAR_ZIdXXbpWQgCDaRR5RtpVyGXCsMLr_Fh8n6S12K0,1344
|
424
424
|
stoobly_agent/config/constants/headers.py,sha256=Hfv7R8_NPXAGaMiZPqywGZDnr0qcVUyfenPb4g465rE,169
|
425
425
|
stoobly_agent/config/constants/intercept_policy.py,sha256=5hIgOft8PQmCRdOHb5OEvEj10tU66DIQF3GYltlWyM8,25
|
@@ -488,7 +488,7 @@ stoobly_agent/lib/api/keys/request_key.py,sha256=68hN0KLdf0FwxSCSjeJZ1uUs526PCbN
|
|
488
488
|
stoobly_agent/lib/api/keys/resource_key.py,sha256=9qrkp3t8iJsScZvKVcBDvVbcfwmP0yEBWy3b1tHi8CM,689
|
489
489
|
stoobly_agent/lib/api/keys/scenario_key.py,sha256=VAc6gayvJS7shWgDL3SAqVET3fmgBefcygXTsKot07U,629
|
490
490
|
stoobly_agent/lib/api/keys/test_key.py,sha256=-MCWp1oYLkJ3S_Pqs62j8KkkssXpT9quKb4YqMSq1Ks,438
|
491
|
-
stoobly_agent/lib/api/keys/uuid_key.py,sha256=
|
491
|
+
stoobly_agent/lib/api/keys/uuid_key.py,sha256=30ZJIEAQHsR1KCsmeALxsKwCaUQtm7pKvFUhLmk0J4I,643
|
492
492
|
stoobly_agent/lib/api/param_builder.py,sha256=50eq0zkqRz5MVezPZMIu69fYSB6z4CD5FG26_IU3eq0,996
|
493
493
|
stoobly_agent/lib/api/projects_resource.py,sha256=7leBuQnlpgUwbYUX445lUC3jy-dzLMpTumeNPrqRc5c,1166
|
494
494
|
stoobly_agent/lib/api/query_param_names_resource.py,sha256=k-3nlyfCOa_Vwj-TMI7v8_4g9qAs50baP073gkStAKE,1710
|
@@ -675,7 +675,7 @@ stoobly_agent/test/app/cli/request/request_list_test.py,sha256=tqMjkODU2i2eDvYyk
|
|
675
675
|
stoobly_agent/test/app/cli/request/request_replay_test.py,sha256=w13NzkXhmBKvoogpQ8CdmBbCzoyqxEQvBZsEkGDCPx0,6237
|
676
676
|
stoobly_agent/test/app/cli/request/request_reset_test.py,sha256=5My6Z452eideAOUun77tWUkuu3_yGhDVxCG1baUF8Zo,1290
|
677
677
|
stoobly_agent/test/app/cli/request/request_response_test.py,sha256=Fu-A8tIn016DKme4WIaPzo3YeFY-CPtTOpaSFigUVVM,1263
|
678
|
-
stoobly_agent/test/app/cli/request/request_snapshot_test.py,sha256=
|
678
|
+
stoobly_agent/test/app/cli/request/request_snapshot_test.py,sha256=3kMmv0CuvnMXLgDQA-_u9S1DIiNOdL63L-IptVuOpf8,6308
|
679
679
|
stoobly_agent/test/app/cli/request/request_test_test.py,sha256=-cJNXKjgryVVfVt-7IN5fIhBwe3NjFoPmeavDH8lAjU,5527
|
680
680
|
stoobly_agent/test/app/cli/scaffold/cli_invoker.py,sha256=_nGDLUsYxqkeqs5DdhvAeXy3IuotpgqKHXKVzu6GDF4,3700
|
681
681
|
stoobly_agent/test/app/cli/scaffold/cli_test.py,sha256=sMNvO845MIu5DVGa1HmwXQDmKDcwrfNTdEb3fK5886w,4557
|
@@ -688,10 +688,10 @@ stoobly_agent/test/app/cli/scenario/scenario_reset_test.py,sha256=QOyytOoFu1FALn
|
|
688
688
|
stoobly_agent/test/app/cli/scenario/scenario_snapshot_test.py,sha256=IAe1l69Smd8a9E6I0CVs8lgqnC4mI4M1EFfUjC4ZHs8,3396
|
689
689
|
stoobly_agent/test/app/cli/scenario/scenario_test_integration_test.py,sha256=BdXGe1xfb79tCCTKtp4sqI6CkZL_KamvQKLK8Wwb4u0,5543
|
690
690
|
stoobly_agent/test/app/cli/snapshot/lifecycle_hooks_migrate.py,sha256=x3x5vHfZ1xmoOpZ0yRSB3kbWbPjfbLk2PJFSa1xOLoU,316
|
691
|
-
stoobly_agent/test/app/cli/snapshot/snapshot_apply_test.py,sha256=
|
691
|
+
stoobly_agent/test/app/cli/snapshot/snapshot_apply_test.py,sha256=mpkTZx8eaFFZU_RKHPcphaNl6zKCIOTJ2i4kY9BZRgQ,32395
|
692
692
|
stoobly_agent/test/app/cli/snapshot/snapshot_copy_test.py,sha256=Yg78-FhSiG_r6Jpm-sN8sn0LjVXTwTOXt6hg8ni2GIY,1953
|
693
693
|
stoobly_agent/test/app/cli/snapshot/snapshot_migrate_test.py,sha256=voEvblK6CMGCrSJDTHVmkUkLXj0auNb78jxlGiiBBQQ,7370
|
694
|
-
stoobly_agent/test/app/cli/snapshot/snapshot_prune_test.py,sha256=
|
694
|
+
stoobly_agent/test/app/cli/snapshot/snapshot_prune_test.py,sha256=bn4yUU7Eb4-6GnwnRaPZPi5Cn7XEaIsrJ_mB7jydgWw,6693
|
695
695
|
stoobly_agent/test/app/cli/snapshot/snapshot_update_test.py,sha256=fILsX2M5j4wuLRP6LJTHe4CPB8gvaEbsSoYmFCHmKVk,4514
|
696
696
|
stoobly_agent/test/app/models/adapters/orm/joined_request_string_adapter_test.py,sha256=a2IHTk3l7aiLyYF7vtqissrk0MFTF2wlUBiaKWyJKfU,2667
|
697
697
|
stoobly_agent/test/app/models/adapters/orm/request/orm_mitmproxy_request_adapter_test.py,sha256=PbJsAaxPUEbF9vM7DX4z858biWf4qlGnvE8KBuy8SgY,2763
|
@@ -707,7 +707,7 @@ stoobly_agent/test/app/models/factories/resource/local_db/helpers/log_test.py,sh
|
|
707
707
|
stoobly_agent/test/app/models/factories/resource/local_db/helpers/tiebreak_scenario_request_test.py,sha256=a1SFLyEyRRLuADvAw6ckQQKORFXvyK1lyrbkaLWx8oU,3399
|
708
708
|
stoobly_agent/test/app/models/factories/resource/local_db/request_adapter_test.py,sha256=Pzq1cBPnP9oSWG-p0c-VoymoHxgp483QmNwmV1b78RA,8453
|
709
709
|
stoobly_agent/test/app/models/factories/resource/local_db/response_adapter_test.py,sha256=9P95EKH5rZGOrmRkRIDlQZqtiLJHk9735og18Ffwpfw,2204
|
710
|
-
stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=
|
710
|
+
stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=dxfL-Qxjo7CWAIdjoCBmI5kW-pkW-YJU0ao7JHCDD80,5
|
711
711
|
stoobly_agent/test/app/models/schemas/.stoobly/db/stoobly_agent.sqlite3,sha256=ch8gNx6zIelLKQx65gwFx_LRNqUD3EC5xcHZ0ukIQiU,188416
|
712
712
|
stoobly_agent/test/app/models/schemas/.stoobly/settings.yml,sha256=vLwMjweKOdod6tSLtIlyBefPQuNXq9wio4kBaODKtAU,726
|
713
713
|
stoobly_agent/test/app/models/schemas/.stoobly/tmp/options.json,sha256=OTRzarwus48CTrItedXCrgQttJHSEZonEYc7R_knvYg,2212
|
@@ -748,8 +748,8 @@ stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml,sha256=1W
|
|
748
748
|
stoobly_agent/test/mock_data/scaffold/index.html,sha256=qJwuYajKZ4ihWZrJQ3BNObV5kf1VGnnm_vqlPJzdqLE,258
|
749
749
|
stoobly_agent/test/mock_data/uspto.yaml,sha256=6U5se7C3o-86J4m9xpOk9Npias399f5CbfWzR87WKwE,7835
|
750
750
|
stoobly_agent/test/test_helper.py,sha256=m_oAI7tmRYCNZdKfNqISWhMv3e44tjeYViQ3nTUfnos,1007
|
751
|
-
stoobly_agent-1.9.
|
752
|
-
stoobly_agent-1.9.
|
753
|
-
stoobly_agent-1.9.
|
754
|
-
stoobly_agent-1.9.
|
755
|
-
stoobly_agent-1.9.
|
751
|
+
stoobly_agent-1.9.2.dist-info/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
|
752
|
+
stoobly_agent-1.9.2.dist-info/METADATA,sha256=qMOKulRLao6AQJC0ctx4h0IyYP6Fd-ACe5NtoyuIY1U,3087
|
753
|
+
stoobly_agent-1.9.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
754
|
+
stoobly_agent-1.9.2.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
|
755
|
+
stoobly_agent-1.9.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|