stoobly-agent 0.33.2__py3-none-any.whl → 0.33.4__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/api/requests_controller.py +2 -0
- stoobly_agent/app/cli/helpers/handle_test_service.py +24 -6
- stoobly_agent/app/cli/helpers/test_replay_context.py +2 -1
- stoobly_agent/app/cli/request_cli.py +2 -1
- stoobly_agent/app/cli/scenario_cli.py +5 -3
- stoobly_agent/app/models/factories/resource/local_db/helpers/create_request_columns_service.py +6 -3
- stoobly_agent/app/models/factories/resource/local_db/request_adapter.py +4 -5
- stoobly_agent/app/models/types/request.py +1 -0
- stoobly_agent/app/models/types/scenario.py +1 -0
- stoobly_agent/app/proxy/handle_test_service.py +11 -6
- stoobly_agent/app/proxy/intercept_settings.py +7 -0
- stoobly_agent/app/proxy/test/context.py +2 -2
- stoobly_agent/app/proxy/test/context_abc.py +3 -2
- stoobly_agent/app/proxy/test/helpers/test_results_builder.py +7 -0
- stoobly_agent/app/proxy/test/helpers/upload_test_service.py +0 -2
- stoobly_agent/app/proxy/test/matchers/context.py +5 -1
- stoobly_agent/config/constants/custom_headers.py +1 -0
- stoobly_agent/db/migrations/2023_05_15_212505_add_uuid_column_to_requests.py +1 -1
- stoobly_agent/db/migrations/2023_05_15_213119_add_uuid_column_to_scenarios.py +1 -1
- stoobly_agent/lib/api/interfaces/tests.py +1 -0
- stoobly_agent/public/{19-es2015.afe15b7c97204b5da3e6.js → 19-es2015.cfb9a99583184965c030.js} +1 -1
- stoobly_agent/public/{19-es5.afe15b7c97204b5da3e6.js → 19-es5.cfb9a99583184965c030.js} +1 -1
- stoobly_agent/public/31-es2015.f4291150f35d54ff19ca.js +1 -0
- stoobly_agent/public/31-es5.f4291150f35d54ff19ca.js +1 -0
- stoobly_agent/public/{35-es2015.ef19536d87c8aff8f629.js → 35-es2015.4281bf4c914cc833cb00.js} +1 -1
- stoobly_agent/public/{35-es5.ef19536d87c8aff8f629.js → 35-es5.4281bf4c914cc833cb00.js} +1 -1
- stoobly_agent/public/37-es2015.6567a0ce4cf87ad7287b.js +1 -0
- stoobly_agent/public/37-es5.6567a0ce4cf87ad7287b.js +1 -0
- stoobly_agent/public/index.html +1 -1
- stoobly_agent/public/{main-es2015.74eedbf8ac279a527ac3.js → main-es2015.3ad631f688af79edb9e7.js} +1 -1
- stoobly_agent/public/{main-es5.74eedbf8ac279a527ac3.js → main-es5.3ad631f688af79edb9e7.js} +1 -1
- stoobly_agent/public/runtime-es2015.ce140e9ace0d883b7982.js +1 -0
- stoobly_agent/public/runtime-es5.ce140e9ace0d883b7982.js +1 -0
- stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
- {stoobly_agent-0.33.2.dist-info → stoobly_agent-0.33.4.dist-info}/METADATA +1 -1
- {stoobly_agent-0.33.2.dist-info → stoobly_agent-0.33.4.dist-info}/RECORD +48 -48
- stoobly_agent/public/31-es2015.198ce7bb981893b0ffb9.js +0 -1
- stoobly_agent/public/31-es5.198ce7bb981893b0ffb9.js +0 -1
- stoobly_agent/public/37-es2015.2691c88dff72bd0e1b98.js +0 -1
- stoobly_agent/public/37-es5.2691c88dff72bd0e1b98.js +0 -1
- stoobly_agent/public/runtime-es2015.8d562cec3ef3d89930a0.js +0 -1
- stoobly_agent/public/runtime-es5.8d562cec3ef3d89930a0.js +0 -1
- /stoobly_agent/public/{12-es2015.7caf8af72ac062656549.js → 12-es2015.e6cbd665db1eb1d3bbed.js} +0 -0
- /stoobly_agent/public/{12-es5.7caf8af72ac062656549.js → 12-es5.e6cbd665db1eb1d3bbed.js} +0 -0
- /stoobly_agent/public/{33-es2015.af3dab68c45d0fa4d762.js → 33-es2015.1de1bb64d23f33c17ef2.js} +0 -0
- /stoobly_agent/public/{33-es5.af3dab68c45d0fa4d762.js → 33-es5.1de1bb64d23f33c17ef2.js} +0 -0
- /stoobly_agent/public/{41-es2015.73c5bfc29200498e1251.js → 41-es2015.8679fbbd8207bda9407c.js} +0 -0
- /stoobly_agent/public/{41-es5.73c5bfc29200498e1251.js → 41-es5.8679fbbd8207bda9407c.js} +0 -0
- /stoobly_agent/public/{42-es2015.bc8a021e2b75feabf80f.js → 42-es2015.bca78151df3a77aa6c5d.js} +0 -0
- /stoobly_agent/public/{42-es5.bc8a021e2b75feabf80f.js → 42-es5.bca78151df3a77aa6c5d.js} +0 -0
- {stoobly_agent-0.33.2.dist-info → stoobly_agent-0.33.4.dist-info}/LICENSE +0 -0
- {stoobly_agent-0.33.2.dist-info → stoobly_agent-0.33.4.dist-info}/WHEEL +0 -0
- {stoobly_agent-0.33.2.dist-info → stoobly_agent-0.33.4.dist-info}/entry_points.txt +0 -0
stoobly_agent/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
COMMAND = 'stoobly-agent'
|
2
|
-
VERSION = '0.33.
|
2
|
+
VERSION = '0.33.4'
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
import pdb
|
3
|
+
import uuid
|
3
4
|
|
4
5
|
from datetime import datetime
|
5
6
|
from urllib.parse import urlparse
|
@@ -63,6 +64,7 @@ class RequestsController:
|
|
63
64
|
request, status = request_model.create(**{
|
64
65
|
**create_params,
|
65
66
|
'scenario_id': scenario_id,
|
67
|
+
'uuid': str(uuid.uuid4()),
|
66
68
|
})
|
67
69
|
|
68
70
|
if context.filter_response(request, status):
|
@@ -23,6 +23,7 @@ class SessionContext(TypedDict):
|
|
23
23
|
passed: int
|
24
24
|
output: TestOutput
|
25
25
|
project_id: int
|
26
|
+
skipped: int
|
26
27
|
test_facade: TestFacade
|
27
28
|
total: int
|
28
29
|
|
@@ -54,6 +55,9 @@ def handle_test_complete(
|
|
54
55
|
|
55
56
|
test = context.test_show_response(session_context['test_facade'])
|
56
57
|
|
58
|
+
if test['skipped']:
|
59
|
+
session_context['skipped'] += 1
|
60
|
+
|
57
61
|
passed = bool(test.get('passed')) if isinstance(test, dict) else False
|
58
62
|
session_context['passed'] += (1 if passed else 0)
|
59
63
|
session_context['total'] += 1
|
@@ -65,7 +69,7 @@ def exit_on_failure(session_context: SessionContext, **options: ExitOnFailureOpt
|
|
65
69
|
if complete == None:
|
66
70
|
complete = True
|
67
71
|
|
68
|
-
if session_context['passed'] != session_context['total']:
|
72
|
+
if session_context['passed'] + session_context['skipped'] != session_context['total']:
|
69
73
|
if not complete:
|
70
74
|
handle_test_session_complete(session_context, format=options.get('format'))
|
71
75
|
|
@@ -112,7 +116,10 @@ def __default_test_complete_formatter(context: ReplayContext, session_context: S
|
|
112
116
|
print_with_decoding(format_request(context))
|
113
117
|
|
114
118
|
if not res['passed']:
|
115
|
-
|
119
|
+
if res['skipped']:
|
120
|
+
passed_message = f"{bcolors.WARNING}skipped{bcolors.ENDC}"
|
121
|
+
else:
|
122
|
+
passed_message = f"{bcolors.FAIL}failed{bcolors.ENDC}"
|
116
123
|
else:
|
117
124
|
passed_message = f"{bcolors.OKGREEN}passed{bcolors.ENDC}"
|
118
125
|
|
@@ -121,7 +128,7 @@ def __default_test_complete_formatter(context: ReplayContext, session_context: S
|
|
121
128
|
if res['log']:
|
122
129
|
print(res['log'])
|
123
130
|
|
124
|
-
if not res['passed']:
|
131
|
+
if not res['passed'] and not res['skipped']:
|
125
132
|
project_id = session_context['project_id']
|
126
133
|
test_facade = session_context['test_facade']
|
127
134
|
expected_response = __get_test_expected_response_with_context(context, project_id, test_facade)
|
@@ -138,21 +145,32 @@ def __default_session_complete_formatter(session_context: SessionContext):
|
|
138
145
|
if 'output' in session_context:
|
139
146
|
print(session_context['output'])
|
140
147
|
|
141
|
-
passed = session_context['passed']
|
142
148
|
total = session_context['total']
|
143
149
|
|
144
150
|
if total > 1:
|
151
|
+
passed = session_context['passed']
|
152
|
+
skipped = session_context['skipped']
|
153
|
+
|
154
|
+
passed_message = f"{passed} / {total} {bcolors.OKGREEN}passed{bcolors.ENDC}"
|
155
|
+
|
156
|
+
skipped_message = ''
|
157
|
+
if skipped:
|
158
|
+
skipped_message = f" {skipped} {bcolors.WARNING}skipped{bcolors.ENDC}"
|
159
|
+
|
145
160
|
if passed == total:
|
146
|
-
print(f"\n{
|
161
|
+
print(f"\n{passed_message}{skipped_message}")
|
147
162
|
else:
|
148
|
-
|
163
|
+
failed_message = f"{total - passed - skipped} {bcolors.FAIL}failed{bcolors.ENDC}"
|
164
|
+
print(f"\n{passed_message} {failed_message}{skipped_message}")
|
149
165
|
|
150
166
|
def __json_session_complete_formatter(session_context: SessionContext):
|
151
167
|
if 'output' not in session_context:
|
152
168
|
return
|
153
169
|
|
154
170
|
session_context['output']['passed'] = session_context['passed']
|
171
|
+
session_context['output']['skipped'] = session_context['skipped']
|
155
172
|
session_context['output']['total'] = session_context['total']
|
173
|
+
|
156
174
|
print(json.dumps(session_context['output']))
|
157
175
|
|
158
176
|
def __get_test_expected_response_with_context(context: ReplayContext, project_id: str, test_facade: TestFacade) -> Union[requests.Response, str]:
|
@@ -73,13 +73,14 @@ class TestReplayContext(ReplayContext):
|
|
73
73
|
'log': self.__build_log(builder),
|
74
74
|
'passed': builder.passed,
|
75
75
|
'project_id': project_id,
|
76
|
+
'skipped': builder.skipped,
|
76
77
|
'strategy': builder.strategy,
|
77
78
|
}
|
78
79
|
|
79
80
|
def __build_log(self, builder: TestResultsBuilder):
|
80
81
|
log = [builder.log]
|
81
82
|
|
82
|
-
if not builder.passed:
|
83
|
+
if not builder.passed and not builder.skipped:
|
83
84
|
log.append("\n" + diff(builder.expected_response, builder.received_response))
|
84
85
|
|
85
86
|
return "\n".join(log)
|
@@ -131,7 +131,7 @@ def list(**kwargs):
|
|
131
131
|
)(f), not is_remote
|
132
132
|
)
|
133
133
|
@click.option('--record', is_flag=True, default=False, help='Replay request and record.')
|
134
|
-
@ConditionalDecorator(lambda f: click.option('--save', is_flag=True, default=False, help='
|
134
|
+
@ConditionalDecorator(lambda f: click.option('--save', is_flag=True, default=False, help='Save results.')(f), is_remote)
|
135
135
|
@click.option('--scenario-key', help='Record to scenario.')
|
136
136
|
@click.option('--scheme', type=click.Choice(['http', 'https']), help='Rewrite request scheme.')
|
137
137
|
@ConditionalDecorator(lambda f: click.option('--trace-id', help='Use existing trace.')(f), is_remote)
|
@@ -264,6 +264,7 @@ def test(**kwargs):
|
|
264
264
|
'aggregate_failures': kwargs['aggregate_failures'],
|
265
265
|
'passed': 0,
|
266
266
|
'project_id': request_key.project_id,
|
267
|
+
'skipped': 0,
|
267
268
|
'test_facade': TestFacade(settings),
|
268
269
|
'total': 0
|
269
270
|
}
|
@@ -274,8 +274,8 @@ if not is_remote:
|
|
274
274
|
'''
|
275
275
|
)
|
276
276
|
@ConditionalDecorator(lambda f: click.option('--remote-project-key', help='Use remote project for endpoint definitions.')(f), is_remote)
|
277
|
-
@ConditionalDecorator(lambda f: click.option('--report-key', help='Save to report.')(f), is_remote)
|
278
|
-
@ConditionalDecorator(lambda f: click.option('--save', is_flag=True, default=False, help='
|
277
|
+
@ConditionalDecorator(lambda f: click.option('--report-key', help='Save results to report.')(f), is_remote)
|
278
|
+
@ConditionalDecorator(lambda f: click.option('--save', is_flag=True, default=False, help='Save results.')(f), is_remote)
|
279
279
|
@click.option('--scheme', help='Rewrite request scheme.')
|
280
280
|
@click.option(
|
281
281
|
'--strategy',
|
@@ -298,6 +298,7 @@ def test(**kwargs):
|
|
298
298
|
|
299
299
|
if kwargs.get('report_key'):
|
300
300
|
validate_report_key(kwargs['report_key'])
|
301
|
+
kwargs['save'] = True # If report_key is set, then intention is to save results to the report
|
301
302
|
|
302
303
|
if len(kwargs['validate']):
|
303
304
|
validate_aliases(kwargs['validate'], assign=kwargs['assign'], format=kwargs['format'], trace_id=kwargs['trace_id'])
|
@@ -315,7 +316,8 @@ def test(**kwargs):
|
|
315
316
|
session_context: SessionContext = {
|
316
317
|
'aggregate_failures': kwargs['aggregate_failures'],
|
317
318
|
'passed': 0,
|
318
|
-
'project_id': scenario_key.project_id,
|
319
|
+
'project_id': scenario_key.project_id,
|
320
|
+
'skipped': 0,
|
319
321
|
'test_facade': TestFacade(settings),
|
320
322
|
'total': 0
|
321
323
|
}
|
stoobly_agent/app/models/factories/resource/local_db/helpers/create_request_columns_service.py
CHANGED
@@ -19,11 +19,14 @@ def build_request_columns(flow: MitmproxyHTTPFlow, joined_request: JoinedRequest
|
|
19
19
|
'control': joined_request.request_string.control,
|
20
20
|
'latency': joined_request.response_string.latency,
|
21
21
|
'raw': joined_request.request_string.get(),
|
22
|
-
'status': flow.response.status_code,
|
23
|
-
'uuid': joined_request.request_string.request_id.strip(),
|
22
|
+
'status': flow.response.status_code,
|
24
23
|
}
|
25
24
|
|
26
|
-
return {
|
25
|
+
return {
|
26
|
+
**request_columns,
|
27
|
+
**params,
|
28
|
+
**{ 'uuid': params.get('uuid') or joined_request.request_string.request_id.strip() }
|
29
|
+
}
|
27
30
|
|
28
31
|
def build_response_columns(flow: MitmproxyHTTPFlow, joined_request: JoinedRequest):
|
29
32
|
response_columns: ResponseColumns = {
|
@@ -43,9 +43,11 @@ class LocalDBRequestAdapter(LocalDBAdapter):
|
|
43
43
|
flow: MitmproxyHTTPFlow = params['flow']
|
44
44
|
joined_request: JoinedRequest = params['joined_request']
|
45
45
|
scenario_id = params.get('scenario_id')
|
46
|
+
uuid = params.get('uuid')
|
47
|
+
|
48
|
+
request_columns = build_request_columns(flow, joined_request, is_deleted=False, scenario_id=scenario_id, uuid=uuid)
|
46
49
|
|
47
50
|
with ORM.instance().db.transaction():
|
48
|
-
request_columns = build_request_columns(flow, joined_request, is_deleted=False, scenario_id=scenario_id)
|
49
51
|
request_record = self.__request_orm.create(**request_columns)
|
50
52
|
|
51
53
|
response_columns = {
|
@@ -53,10 +55,7 @@ class LocalDBRequestAdapter(LocalDBAdapter):
|
|
53
55
|
**build_response_columns(flow, joined_request),
|
54
56
|
}
|
55
57
|
|
56
|
-
|
57
|
-
if not response_record:
|
58
|
-
request_record.delete()
|
59
|
-
return self.internal_error('Could not create requeset response')
|
58
|
+
self.__response_orm.create(**response_columns)
|
60
59
|
|
61
60
|
return self.success({
|
62
61
|
'list': [ORMToStooblyRequestTransformer(request_record, {}).transform()],
|
@@ -17,7 +17,6 @@ from .mock.context import MockContext
|
|
17
17
|
from .test.helpers.test_results_builder import TestResultsBuilder
|
18
18
|
from .test.helpers.upload_test_service import inject_upload_test
|
19
19
|
from .test.context_abc import TestContextABC as TestContext
|
20
|
-
from .test.helpers.diff_service import diff
|
21
20
|
from .test.test_service import test
|
22
21
|
|
23
22
|
LOG_ID = 'HandleTest'
|
@@ -54,23 +53,29 @@ def __decorate_test_id(flow: MitmproxyHTTPFlow, test_response: TestShowResponse)
|
|
54
53
|
def __handle_mock_success(test_context: TestContext) -> None:
|
55
54
|
flow: MitmproxyHTTPFlow = test_context.flow
|
56
55
|
settings = Settings.instance()
|
56
|
+
|
57
57
|
test_context.with_endpoints_resource(EndpointsResource(settings.remote.api_url, settings.remote.api_key))
|
58
58
|
|
59
59
|
__test_hook(lifecycle_hooks.BEFORE_TEST, test_context)
|
60
60
|
|
61
|
-
|
62
|
-
|
61
|
+
intercept_settings = test_context.intercept_settings
|
62
|
+
if intercept_settings.test_skip:
|
63
|
+
passed, log = (False, '')
|
64
|
+
skipped = True
|
65
|
+
else:
|
66
|
+
# Run test
|
67
|
+
passed, log = test(test_context)
|
68
|
+
skipped = False
|
63
69
|
|
64
70
|
request_id = test_context.mock_request_id
|
65
71
|
if request_id:
|
66
|
-
|
67
|
-
|
68
|
-
expected = test_context.cached_expected_response_content
|
72
|
+
expected = test_context.cached_rewritten_expected_response_content
|
69
73
|
upload_test_data = {
|
70
74
|
'expected_response': expected,
|
71
75
|
'log': log,
|
72
76
|
'passed': passed,
|
73
77
|
'request_id': request_id,
|
78
|
+
'skipped': skipped,
|
74
79
|
'status': flow.response.status_code,
|
75
80
|
'strategy': test_context.strategy
|
76
81
|
}
|
@@ -215,6 +215,13 @@ class InterceptSettings:
|
|
215
215
|
return not not int(self.__headers[custom_headers.TEST_SAVE_RESULTS])
|
216
216
|
|
217
217
|
return False
|
218
|
+
|
219
|
+
@property
|
220
|
+
def test_skip(self):
|
221
|
+
if self.__headers and custom_headers.TEST_SKIP in self.__headers:
|
222
|
+
return True
|
223
|
+
|
224
|
+
return False
|
218
225
|
|
219
226
|
@property
|
220
227
|
def test_strategy(self):
|
@@ -54,11 +54,11 @@ class TestContext(TestContextABC):
|
|
54
54
|
return self
|
55
55
|
|
56
56
|
@property
|
57
|
-
def
|
57
|
+
def cached_rewritten_expected_response_content(self) -> FuzzyContent:
|
58
58
|
if not self.__cached_rewritten_expected_response_content:
|
59
59
|
return self.rewritten_expected_response_content
|
60
60
|
|
61
|
-
return
|
61
|
+
return self.__cached_rewritten_expected_response_content
|
62
62
|
|
63
63
|
@property
|
64
64
|
def endpoint(self) -> EndpointFacade:
|
@@ -5,6 +5,7 @@ from typing import Union
|
|
5
5
|
|
6
6
|
from stoobly_agent.app.proxy.test.helpers.endpoint_facade import EndpointFacade
|
7
7
|
from stoobly_agent.app.proxy.test.helpers.request_component_names_facade import RequestComponentNamesFacade
|
8
|
+
from stoobly_agent.app.proxy.intercept_settings import InterceptSettings
|
8
9
|
from stoobly_agent.lib.api.interfaces.endpoints import EndpointShowResponse
|
9
10
|
from stoobly_agent.lib.orm.trace import Trace
|
10
11
|
|
@@ -20,7 +21,7 @@ class TestContextABC(abc.ABC):
|
|
20
21
|
|
21
22
|
@property
|
22
23
|
@abc.abstractmethod
|
23
|
-
def
|
24
|
+
def cached_rewritten_expected_response_content(self) -> FuzzyContent:
|
24
25
|
pass
|
25
26
|
|
26
27
|
@property
|
@@ -70,7 +71,7 @@ class TestContextABC(abc.ABC):
|
|
70
71
|
|
71
72
|
@property
|
72
73
|
@abc.abstractmethod
|
73
|
-
def intercept_settings(self):
|
74
|
+
def intercept_settings(self) -> InterceptSettings:
|
74
75
|
pass
|
75
76
|
|
76
77
|
@property
|
@@ -19,6 +19,7 @@ class TestResultsBuilder():
|
|
19
19
|
self.__passed = test_data.get('passed')
|
20
20
|
self.__request_id = test_data.get('request_id')
|
21
21
|
self.__received_response = test_data.get('received_response')
|
22
|
+
self.__skipped = test_data.get('skipped')
|
22
23
|
self.__status = test_data.get('status')
|
23
24
|
self.__strategy = test_data.get('strategy')
|
24
25
|
|
@@ -42,6 +43,10 @@ class TestResultsBuilder():
|
|
42
43
|
def received_response(self):
|
43
44
|
return self.__received_response
|
44
45
|
|
46
|
+
@property
|
47
|
+
def skipped(self):
|
48
|
+
return self.__skipped
|
49
|
+
|
45
50
|
@property
|
46
51
|
def status(self):
|
47
52
|
return self.__status
|
@@ -83,6 +88,7 @@ class TestResultsBuilder():
|
|
83
88
|
'log': self.__log,
|
84
89
|
'passed': self.__passed,
|
85
90
|
'request_id': self.__request_id,
|
91
|
+
'skipped': self.__skipped,
|
86
92
|
'status': self.__status,
|
87
93
|
'strategy': self.__strategy,
|
88
94
|
}
|
@@ -119,6 +125,7 @@ class TestResultsBuilder():
|
|
119
125
|
self.__log = test_data.get('log')
|
120
126
|
self.__passed = test_data.get('passed')
|
121
127
|
self.__request_id = test_data.get('request_id')
|
128
|
+
self.__skipped = test_data.get('skipped')
|
122
129
|
self.__status = test_data.get('status')
|
123
130
|
self.__strategy = test_data.get('strategy')
|
124
131
|
|
@@ -213,7 +213,11 @@ class MatchContext():
|
|
213
213
|
|
214
214
|
def __param_name_matches(self, query, param_names: List[ResponseParamName]) -> bool:
|
215
215
|
for param_name in param_names:
|
216
|
-
|
216
|
+
# Not all components will have a query property,
|
217
|
+
# If query property does not exist, then use name property
|
218
|
+
_query = param_name['query'] if 'query' in param_name else param_name['name']
|
219
|
+
|
220
|
+
if _query == query:
|
217
221
|
return True
|
218
222
|
|
219
223
|
return False
|
@@ -20,6 +20,7 @@ SERVICE_URL = 'X-Service-Url'
|
|
20
20
|
TEST_FILTER = 'X-Test-Filter'
|
21
21
|
TEST_ID = 'X-Stoobly-Test-Id'
|
22
22
|
TEST_SAVE_RESULTS = 'X-Stoobly-Test-Save-Results'
|
23
|
+
TEST_SKIP = 'X-Stoobly-Test-Skip'
|
23
24
|
TEST_STRATEGY = 'X-Test-Strategy'
|
24
25
|
TRACE_ID = 'X-Stoobly-Trace-Id'
|
25
26
|
TRACE_REQUEST_ID = 'X-Stoobly-Trace-Request-Id'
|
@@ -13,7 +13,7 @@ class AddUuidColumnToRequests(Migration):
|
|
13
13
|
Run the migrations.
|
14
14
|
"""
|
15
15
|
with self.schema.table('requests') as table:
|
16
|
-
table.string('uuid', 36).default('').index()
|
16
|
+
table.string('uuid', 36).default('').index().unique()
|
17
17
|
|
18
18
|
for request in Request.all():
|
19
19
|
control = RequestStringControl(request.control)
|
@@ -11,7 +11,7 @@ class AddUuidColumnToScenarios(Migration):
|
|
11
11
|
Run the migrations.
|
12
12
|
"""
|
13
13
|
with self.schema.table('scenarios') as table:
|
14
|
-
table.string('uuid', 36).index().
|
14
|
+
table.string('uuid', 36).default('').index().unique()
|
15
15
|
|
16
16
|
for scenario in Scenario.all():
|
17
17
|
scenario.update(uuid=str(uuid.uuid4()))
|