stoobly-agent 1.0.7__py3-none-any.whl → 1.0.8__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.
Files changed (29) hide show
  1. stoobly_agent/__init__.py +1 -1
  2. stoobly_agent/app/cli/scaffold/constants.py +9 -1
  3. stoobly_agent/app/cli/scaffold/docker/constants.py +6 -0
  4. stoobly_agent/app/cli/scaffold/docker/workflow/builder.py +0 -2
  5. stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py +1 -1
  6. stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py +0 -1
  7. stoobly_agent/app/cli/scaffold/managed_services_docker_compose.py +9 -0
  8. stoobly_agent/app/cli/scaffold/service_command.py +3 -1
  9. stoobly_agent/app/cli/scaffold/service_config.py +2 -1
  10. stoobly_agent/app/cli/scaffold/service_docker_compose.py +15 -0
  11. stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py +234 -0
  12. stoobly_agent/app/cli/scaffold/templates/constants.py +3 -3
  13. stoobly_agent/app/cli/scaffold/validate_command.py +59 -0
  14. stoobly_agent/app/cli/scaffold/validate_exceptions.py +5 -0
  15. stoobly_agent/app/cli/scaffold/workflow.py +22 -1
  16. stoobly_agent/app/cli/scaffold/workflow_run_command.py +2 -1
  17. stoobly_agent/app/cli/scaffold/workflow_validate_command.py +94 -0
  18. stoobly_agent/app/cli/scaffold_cli.py +40 -2
  19. stoobly_agent/config/data_dir.py +10 -2
  20. stoobly_agent/test/app/cli/scaffold/e2e_test.py +428 -0
  21. stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
  22. stoobly_agent/test/mock_data/scaffold/docker-compose-assets-service.yml +18 -0
  23. stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml +16 -0
  24. stoobly_agent/test/mock_data/scaffold/index.html +12 -0
  25. {stoobly_agent-1.0.7.dist-info → stoobly_agent-1.0.8.dist-info}/METADATA +2 -1
  26. {stoobly_agent-1.0.7.dist-info → stoobly_agent-1.0.8.dist-info}/RECORD +29 -19
  27. {stoobly_agent-1.0.7.dist-info → stoobly_agent-1.0.8.dist-info}/LICENSE +0 -0
  28. {stoobly_agent-1.0.7.dist-info → stoobly_agent-1.0.8.dist-info}/WHEEL +0 -0
  29. {stoobly_agent-1.0.7.dist-info → stoobly_agent-1.0.8.dist-info}/entry_points.txt +0 -0
@@ -1,3 +1,4 @@
1
+ import pdb
1
2
  import os
2
3
  import shutil
3
4
 
@@ -16,6 +17,8 @@ class DataDir:
16
17
  if DataDir._instances.get(path):
17
18
  raise RuntimeError('Call instance() instead')
18
19
  else:
20
+ self.__path = path
21
+
19
22
  if path:
20
23
  self.__data_dir_path = os.path.join(path, DATA_DIR_NAME)
21
24
  else:
@@ -35,6 +38,9 @@ class DataDir:
35
38
  if not os.path.exists(self.__data_dir_path):
36
39
  self.create(os.path.dirname(self.__data_dir_path))
37
40
 
41
+ def __repr__(self) -> str:
42
+ return self.path
43
+
38
44
  @classmethod
39
45
  def instance(cls, path: str = None):
40
46
  if not cls._instances:
@@ -58,7 +64,7 @@ class DataDir:
58
64
 
59
65
  @property
60
66
  def path(self):
61
- if os.environ.get(ENV) == 'test':
67
+ if not self.__path and os.environ.get(ENV) == 'test':
62
68
  test_path = os.path.join(self.__data_dir_path, 'tmp', DATA_DIR_NAME)
63
69
 
64
70
  if not os.path.exists(test_path):
@@ -212,8 +218,10 @@ class DataDir:
212
218
  if not os.path.exists(self.__data_dir_path):
213
219
  os.mkdir(self.__data_dir_path)
214
220
 
221
+ # Create the certs_dir_path if it doesn't exist
222
+ self.certs_dir_path
215
223
  # Create tmp folder
216
- os.mkdir(os.path.join(self.__data_dir_path, 'tmp'))
224
+ os.makedirs(os.path.join(self.__data_dir_path, 'tmp'), exist_ok=True)
217
225
 
218
226
  with open(os.path.join(self.__data_dir_path, '.gitignore'), 'w') as fp:
219
227
  fp.write(
@@ -0,0 +1,428 @@
1
+ from pathlib import Path
2
+ import pathlib
3
+ import pdb
4
+ import shutil
5
+
6
+ from click.testing import CliRunner
7
+ import docker
8
+ import pytest
9
+
10
+ from stoobly_agent.app.cli import scaffold
11
+ from stoobly_agent.app.cli.scaffold.app import App
12
+ from stoobly_agent.app.cli.scaffold.constants import (
13
+ WORKFLOW_RECORD_TYPE,
14
+ WORKFLOW_TEST_TYPE,
15
+ )
16
+ from stoobly_agent.app.cli.scaffold.constants import DOCKER_NAMESPACE
17
+ from stoobly_agent.app.cli.scaffold.managed_services_docker_compose import (
18
+ ManagedServicesDockerCompose,
19
+ )
20
+ from stoobly_agent.app.cli.scaffold.service_docker_compose import ServiceDockerCompose
21
+ from stoobly_agent.app.cli.scaffold.service_workflow_validate_command import (
22
+ ServiceWorkflowValidateCommand,
23
+ )
24
+ from stoobly_agent.app.cli.scaffold.workflow_validate_command import (
25
+ WorkflowValidateCommand,
26
+ )
27
+ from stoobly_agent.config.data_dir import DATA_DIR_NAME, DataDir
28
+ from stoobly_agent.test.test_helper import reset
29
+
30
+
31
+ @pytest.mark.e2e
32
+ class TestScaffoldE2e():
33
+
34
+ @pytest.fixture(scope='module', autouse=True)
35
+ def settings(self):
36
+ return reset()
37
+
38
+ @pytest.fixture(scope='module')
39
+ def runner(self):
40
+ yield CliRunner()
41
+
42
+ @pytest.fixture(scope='class')
43
+ def docker_client(self):
44
+ yield docker.from_env()
45
+
46
+ @pytest.fixture(scope='class')
47
+ def app_name(self):
48
+ yield "0.0.1"
49
+
50
+ @pytest.fixture(scope='class', autouse=True)
51
+ def temp_dir(self):
52
+ data_dir_path = DataDir.instance().path
53
+ tmp_path = data_dir_path[:data_dir_path.rfind('/')]
54
+
55
+ yield tmp_path
56
+
57
+ @pytest.fixture(scope='class', autouse=True)
58
+ def app_dir_path(self, temp_dir, app_name):
59
+ yield temp_dir
60
+
61
+ @pytest.fixture(scope='class')
62
+ def mock_data_directory_path(self):
63
+ yield Path(__file__).parent.parent.parent.parent / 'mock_data'
64
+
65
+ @pytest.fixture(scope='class')
66
+ def local_service_mock_docker_compose_path(self, mock_data_directory_path):
67
+ path = mock_data_directory_path / "scaffold" / "docker-compose-local-service.yml"
68
+ yield path
69
+
70
+ @pytest.fixture(scope='class')
71
+ def hostname(self):
72
+ yield "http.badssl.com"
73
+
74
+ @pytest.fixture(scope='class')
75
+ def https_service_hostname(self):
76
+ yield "example.com"
77
+
78
+ @pytest.fixture(scope='class')
79
+ def external_service_name(self):
80
+ yield "external-service"
81
+
82
+ @pytest.fixture(scope='class')
83
+ def external_https_service_name(self):
84
+ yield "external-https-service"
85
+
86
+ @pytest.fixture(scope='class')
87
+ def local_hostname(self):
88
+ yield "my-httpbin.com"
89
+
90
+ @pytest.fixture(scope='class')
91
+ def local_service_name(self):
92
+ yield "my-httpbin"
93
+
94
+
95
+ class TestRecordWorkflow():
96
+ @pytest.fixture(scope='class', autouse=True)
97
+ def target_workflow_name(self):
98
+ yield WORKFLOW_RECORD_TYPE
99
+
100
+ @pytest.fixture(scope='class')
101
+ def managed_services_docker_compose(self, target_workflow_name):
102
+ yield ManagedServicesDockerCompose(target_workflow_name=target_workflow_name)
103
+
104
+ @pytest.fixture(scope='class')
105
+ def external_service_docker_compose(self, app_dir_path, target_workflow_name, external_service_name, hostname):
106
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=external_service_name, hostname=hostname)
107
+
108
+ @pytest.fixture(scope='class')
109
+ def external_https_service_docker_compose(self, app_dir_path, target_workflow_name, external_https_service_name, https_service_hostname):
110
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=external_https_service_name, hostname=https_service_hostname)
111
+
112
+ @pytest.fixture(scope='class')
113
+ def local_service_docker_compose(self, app_dir_path, target_workflow_name, local_service_name, local_hostname):
114
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=local_service_name, hostname=local_hostname)
115
+
116
+ @pytest.fixture(scope='class', autouse=True)
117
+ def setup_docker_composes(self, managed_services_docker_compose, external_service_docker_compose, local_service_docker_compose):
118
+ self.managed_services_docker_compose = managed_services_docker_compose
119
+ self.external_service_docker_compose = external_service_docker_compose
120
+ self.local_service_docker_compose = local_service_docker_compose
121
+
122
+ @pytest.fixture(scope="class", autouse=True)
123
+ def create_scaffold_setup(self, runner, app_dir_path, app_name, target_workflow_name, external_service_docker_compose, external_https_service_docker_compose, local_service_docker_compose, local_service_mock_docker_compose_path):
124
+ TestScaffoldE2e.cli_app_create(runner, app_dir_path, app_name)
125
+
126
+ # Create external user defined service
127
+ TestScaffoldE2e.cli_service_create(runner, app_dir_path, external_service_docker_compose.hostname, external_service_docker_compose.service_name, False)
128
+ TestScaffoldE2e.cli_service_create(runner, app_dir_path, external_https_service_docker_compose.hostname, external_https_service_docker_compose.service_name, True)
129
+
130
+ # Create local user defined service
131
+ TestScaffoldE2e.cli_service_create(runner, app_dir_path, local_service_docker_compose.hostname, local_service_docker_compose.service_name, False)
132
+
133
+ # Validate docker-compose path exists
134
+ destination_path = Path(local_service_docker_compose.docker_compose_path)
135
+ assert destination_path.is_file()
136
+ # Add user defined Docker Compose file for the local service
137
+ shutil.copyfile(local_service_mock_docker_compose_path, destination_path)
138
+
139
+ # Record workflow doesn't have a fixtures folder
140
+
141
+ # Generate certs
142
+ TestScaffoldE2e.cli_app_mkcert(runner, app_dir_path)
143
+
144
+ TestScaffoldE2e.cli_workflow_run(runner, app_dir_path, target_workflow_name)
145
+
146
+ @pytest.fixture(scope="class", autouse=True)
147
+ def cleanup_after_all(self, runner, app_dir_path, target_workflow_name):
148
+ yield
149
+ TestScaffoldE2e.cli_workflow_stop(runner, app_dir_path, target_workflow_name)
150
+
151
+ def test_core_components(self, app_dir_path, target_workflow_name):
152
+ app = App(app_dir_path, DOCKER_NAMESPACE)
153
+ config = {
154
+ 'workflow_name': target_workflow_name,
155
+ 'service_name': 'build'
156
+ }
157
+
158
+ command = WorkflowValidateCommand(app, **config)
159
+ command.validate()
160
+
161
+ def test_external_service(self, external_service_docker_compose: ServiceDockerCompose, app_dir_path, target_workflow_name):
162
+ app = App(app_dir_path, DOCKER_NAMESPACE)
163
+ config = {
164
+ 'workflow_name': target_workflow_name,
165
+ 'service_name': external_service_docker_compose.service_name
166
+ }
167
+
168
+ command = ServiceWorkflowValidateCommand(app, **config)
169
+ command.validate()
170
+
171
+ def test_local_service(self, app_dir_path, target_workflow_name, local_service_docker_compose: ServiceDockerCompose):
172
+ app = App(app_dir_path, DOCKER_NAMESPACE)
173
+ config = {
174
+ 'workflow_name': target_workflow_name,
175
+ 'service_name': local_service_docker_compose.service_name
176
+ }
177
+
178
+ command = ServiceWorkflowValidateCommand(app, **config)
179
+ command.validate()
180
+
181
+
182
+ class TestTestWorkflow():
183
+ @pytest.fixture(scope='class')
184
+ def assets_service_mock_docker_compose_path(self, mock_data_directory_path):
185
+ path = mock_data_directory_path / "scaffold" / "docker-compose-assets-service.yml"
186
+ yield path
187
+
188
+ @pytest.fixture(scope='class')
189
+ def assets_service_assets_path(self, mock_data_directory_path):
190
+ path = mock_data_directory_path / "scaffold" / "index.html"
191
+ yield path
192
+
193
+ @pytest.fixture(scope='class', autouse=True)
194
+ def target_workflow_name(self):
195
+ yield WORKFLOW_TEST_TYPE
196
+
197
+ @pytest.fixture(scope='class')
198
+ def assets_service_name(self):
199
+ yield "assets"
200
+
201
+ @pytest.fixture(scope='class')
202
+ def assets_hostname(self):
203
+ yield "assets"
204
+
205
+ @pytest.fixture(scope='class')
206
+ def managed_services_docker_compose(self, target_workflow_name):
207
+ yield ManagedServicesDockerCompose(target_workflow_name=target_workflow_name)
208
+
209
+ @pytest.fixture(scope='class')
210
+ def external_service_docker_compose(self, app_dir_path, target_workflow_name, external_service_name, hostname):
211
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=external_service_name, hostname=hostname)
212
+
213
+ @pytest.fixture(scope='class')
214
+ def local_service_docker_compose(self, app_dir_path, target_workflow_name, local_service_name, local_hostname):
215
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=local_service_name, hostname=local_hostname)
216
+
217
+ @pytest.fixture(scope='class')
218
+ def assets_service_docker_compose(self, app_dir_path, target_workflow_name, assets_service_name, assets_hostname):
219
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=assets_service_name, hostname=assets_hostname)
220
+
221
+ @pytest.fixture(scope='class', autouse=True)
222
+ def setup_docker_composes(self, managed_services_docker_compose, external_service_docker_compose, local_service_docker_compose, assets_service_docker_compose):
223
+ self.managed_services_docker_compose = managed_services_docker_compose
224
+ self.external_service_docker_compose = external_service_docker_compose
225
+ self.local_service_docker_compose = local_service_docker_compose
226
+ self.assets_service_docker_compose = assets_service_docker_compose
227
+
228
+ @pytest.fixture(scope="class", autouse=True)
229
+ def create_scaffold_setup(self, runner, app_name, app_dir_path, target_workflow_name, external_service_docker_compose, local_service_docker_compose, assets_service_docker_compose, mock_data_directory_path, assets_service_mock_docker_compose_path):
230
+
231
+ TestScaffoldE2e.cli_app_create(runner, app_dir_path, app_name)
232
+
233
+ # Create external user defined service
234
+ TestScaffoldE2e.cli_service_create(runner, app_dir_path, external_service_docker_compose.hostname, external_service_docker_compose.service_name, False)
235
+ # Create local user defined services
236
+ TestScaffoldE2e.cli_service_create(runner, app_dir_path, local_service_docker_compose.hostname, local_service_docker_compose.service_name, False)
237
+ TestScaffoldE2e.cli_service_create_assets(runner, app_dir_path, assets_service_docker_compose.hostname, assets_service_docker_compose.service_name, False)
238
+
239
+ # Don't run the local user defined service in the 'test' workflow
240
+ # So don't copy the Docker Compose file over
241
+
242
+ # Add user defined Docker Compose file for the assets service
243
+ destination_path = Path(assets_service_docker_compose.docker_compose_path)
244
+ assert destination_path.is_file()
245
+ shutil.copyfile(assets_service_mock_docker_compose_path, destination_path)
246
+
247
+ TestScaffoldE2e.cli_service_create_assets(runner, app_dir_path, assets_service_docker_compose.hostname, assets_service_docker_compose.service_name, False)
248
+
249
+ # Add assets for assets service
250
+ data_dir_path = DataDir.instance().path
251
+ destination_assets_path = f"{data_dir_path}/docker/{assets_service_docker_compose.service_name}/{target_workflow_name}/index.html"
252
+ destination_path = Path(destination_assets_path)
253
+ assets_mock_path = mock_data_directory_path / "scaffold" / "index.html"
254
+ shutil.copyfile(assets_mock_path, destination_path)
255
+
256
+ # Created shared file in fixtures folder
257
+ app = App(app_dir_path, DOCKER_NAMESPACE)
258
+ config = {
259
+ 'workflow_name': target_workflow_name,
260
+ 'service_name': external_service_docker_compose.service_name
261
+ }
262
+ command = ServiceWorkflowValidateCommand(app, **config)
263
+ with open(f"{command.fixtures_dir_path}/shared_file.txt", 'w') as file:
264
+ file.write('this is a shared file')
265
+
266
+ TestScaffoldE2e.cli_workflow_run(runner, app_dir_path, target_workflow_name=target_workflow_name)
267
+
268
+ @pytest.fixture(scope="class", autouse=True)
269
+ def cleanup_after_all(self, runner, app_dir_path, target_workflow_name):
270
+ yield
271
+ TestScaffoldE2e.cli_workflow_stop(runner, app_dir_path, target_workflow_name)
272
+
273
+ def test_no_core_components(self, app_dir_path, target_workflow_name):
274
+ app = App(app_dir_path, DOCKER_NAMESPACE)
275
+ config = {
276
+ 'workflow_name': target_workflow_name,
277
+ 'service_name': 'build'
278
+ }
279
+
280
+ command = WorkflowValidateCommand(app, **config)
281
+ command.validate()
282
+
283
+ def test_user_services(self, app_dir_path, target_workflow_name, external_service_docker_compose, local_service_docker_compose):
284
+ app = App(app_dir_path, DOCKER_NAMESPACE)
285
+
286
+ config = {
287
+ 'workflow_name': target_workflow_name,
288
+ 'service_name': external_service_docker_compose.service_name
289
+ }
290
+ command = ServiceWorkflowValidateCommand(app, **config)
291
+ command.validate()
292
+
293
+ config = {
294
+ 'workflow_name': target_workflow_name,
295
+ 'service_name': local_service_docker_compose.service_name
296
+ }
297
+ command = ServiceWorkflowValidateCommand(app, **config)
298
+ command.validate()
299
+
300
+ def test_tests(self):
301
+ # This is covered by test_assets
302
+ pass
303
+
304
+ def test_assets(self, app_dir_path, target_workflow_name):
305
+
306
+ app = App(app_dir_path, DOCKER_NAMESPACE)
307
+ config = {
308
+ 'workflow_name': target_workflow_name,
309
+ 'service_name': 'assets'
310
+ }
311
+
312
+ command = ServiceWorkflowValidateCommand(app, **config)
313
+ command.validate()
314
+
315
+ @staticmethod
316
+ def cli_app_create(runner: CliRunner, app_dir_path: str, app_name: str):
317
+ pathlib.Path(f"{app_dir_path}/{DATA_DIR_NAME}").mkdir(parents=True, exist_ok=True)
318
+
319
+ result = runner.invoke(scaffold, ['app', 'create',
320
+ '--app-dir-path', app_dir_path,
321
+ '--force',
322
+ app_name
323
+ ])
324
+
325
+ assert result.exit_code == 0
326
+ output = result.stdout
327
+ assert not output
328
+
329
+ @staticmethod
330
+ def cli_app_mkcert(runner: CliRunner, app_dir_path: str):
331
+ result = runner.invoke(scaffold, ['app', 'mkcert',
332
+ '--app-dir-path', app_dir_path,
333
+ '--context-dir-path', app_dir_path,
334
+ ])
335
+
336
+ assert result.exit_code == 0
337
+ output = result.stdout
338
+ assert not output
339
+
340
+
341
+ @staticmethod
342
+ def cli_service_create(runner: CliRunner, app_dir_path: str, hostname: str, service_name: str, https: bool):
343
+ scheme = 'http'
344
+ port = '80'
345
+ if https == True:
346
+ scheme = 'https'
347
+ port = '443'
348
+
349
+ result = runner.invoke(scaffold, ['service', 'create',
350
+ '--app-dir-path', app_dir_path,
351
+ '--env', 'TEST',
352
+ '--force',
353
+ '--hostname', hostname,
354
+ '--scheme', scheme,
355
+ '--port', port,
356
+ '--workflow', 'mock',
357
+ '--workflow', 'record',
358
+ '--workflow', 'test',
359
+ service_name
360
+ ])
361
+ assert result.exit_code == 0
362
+ output = result.stdout
363
+ assert not output
364
+
365
+ # Specific flags for assets
366
+ @staticmethod
367
+ def cli_service_create_assets(runner: CliRunner, app_dir_path: str, hostname: str, service_name: str, https: bool):
368
+ scheme = 'http'
369
+ port = '80'
370
+ if https == True:
371
+ scheme = 'https'
372
+ port = '443'
373
+ proxy_mode_reverse_spec = f"reverse:{scheme}://{hostname}:8080"
374
+
375
+ result = runner.invoke(scaffold, ['service', 'create',
376
+ '--app-dir-path', app_dir_path,
377
+ '--force',
378
+ '--hostname', hostname,
379
+ '--scheme', scheme,
380
+ '--port', port,
381
+ '--proxy-mode', proxy_mode_reverse_spec,
382
+ '--detached',
383
+ '--workflow', 'test',
384
+ service_name
385
+ ])
386
+ assert result.exit_code == 0
387
+ output = result.stdout
388
+ assert not output
389
+
390
+ @staticmethod
391
+ def cli_workflow_create(runner: CliRunner, app_dir_path: str, service_name: str):
392
+ result = runner.invoke(scaffold, ['workflow', 'create',
393
+ '--app-dir-path', app_dir_path,
394
+ '--service', service_name,
395
+ '--template', 'mock',
396
+ 'ci',
397
+ ])
398
+
399
+ assert result.exit_code == 0
400
+ output = result.stdout
401
+ assert not output
402
+
403
+ @staticmethod
404
+ def cli_workflow_run(runner: CliRunner, app_dir_path: str, target_workflow_name: str):
405
+ command = ['workflow', 'run',
406
+ '--app-dir-path', app_dir_path,
407
+ '--context-dir-path', app_dir_path,
408
+ target_workflow_name,
409
+ ]
410
+ result = runner.invoke(scaffold, command)
411
+
412
+ assert result.exit_code == 0
413
+ output = result.stdout
414
+ assert output
415
+
416
+ @staticmethod
417
+ def cli_workflow_stop(runner: CliRunner, app_dir_path: str, target_workflow_name: str):
418
+ command = ['workflow', 'stop',
419
+ '--app-dir-path', app_dir_path,
420
+ '--context-dir-path', app_dir_path,
421
+ target_workflow_name,
422
+ ]
423
+ result = runner.invoke(scaffold, command)
424
+
425
+ assert result.exit_code == 0
426
+ output = result.stdout
427
+ assert output
428
+
@@ -1 +1 @@
1
- 1.0.5
1
+ 1.0.7
@@ -0,0 +1,18 @@
1
+ # Define services here
2
+
3
+ networks:
4
+ app:
5
+ external: true
6
+ name: ${APP_NETWORK}
7
+
8
+ services:
9
+ assets:
10
+ image: nginx:1.27
11
+ hostname: assets
12
+ networks:
13
+ - app
14
+ volumes:
15
+ - ./index.html:/usr/share/nginx/html/index.html
16
+ profiles: &id001
17
+ - test
18
+
@@ -0,0 +1,16 @@
1
+ # Define services here
2
+
3
+ networks:
4
+ gateway:
5
+ external: true
6
+ name: ${APP_NETWORK}
7
+
8
+ services:
9
+ my-httpbin:
10
+ image: kennethreitz/httpbin:latest
11
+ hostname: my-httpbin.com
12
+ networks:
13
+ - gateway
14
+ profiles: &id001
15
+ - record
16
+
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Welcome to NGINX</title>
7
+ </head>
8
+ <body>
9
+ <h1>Hello, NGINX is serving this page!</h1>
10
+ </body>
11
+ </html>
12
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: stoobly-agent
3
- Version: 1.0.7
3
+ Version: 1.0.8
4
4
  Summary: Record, mock, and test HTTP(s) requests. CLI agent for Stoobly
5
5
  License: Apache-2.0
6
6
  Author: Matt Le
@@ -16,6 +16,7 @@ Requires-Dist: click (>=8.1.0,<9.0.0)
16
16
  Requires-Dist: diff-match-patch (>=20230430,<20230431)
17
17
  Requires-Dist: distro (>=1.6.0,<1.7.0)
18
18
  Requires-Dist: dnspython (>=2.6.1,<2.7.0)
19
+ Requires-Dist: docker (>=7.1.0,<8.0)
19
20
  Requires-Dist: httptools (>=0.4.0)
20
21
  Requires-Dist: jmespath (>=1.0.0)
21
22
  Requires-Dist: mergedeep (>=1.3.0,<1.3.4)
@@ -1,4 +1,4 @@
1
- stoobly_agent/__init__.py,sha256=wSw9-Gxd6f7Hco-PFFshn84Ed5NXRZzPr_pJdTrL_eY,44
1
+ stoobly_agent/__init__.py,sha256=YRJ2IyOFYfNMitHnDEgevFuLZ3X0HHY8moxXjMFFabk,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=jf4fkqjOiCeI2IM5Ro7ie0v_C6y0-7-5TIE_IKMPOfg,5513
@@ -73,11 +73,11 @@ stoobly_agent/app/cli/scaffold/app_config.py,sha256=ZAHGovwxFy3zICfusj9_gUC_FBTI
73
73
  stoobly_agent/app/cli/scaffold/app_create_command.py,sha256=G4q-arXJH0uf6kagiWk26VqKG4zpOngxvJappxIkt-0,568
74
74
  stoobly_agent/app/cli/scaffold/command.py,sha256=klpsgL6V7b2DRHpN33pl-QlmntDkvDO_dsF5JziYnL8,245
75
75
  stoobly_agent/app/cli/scaffold/config.py,sha256=HZU5tkvr3dkPr4JMXZtrJlu2wxxO-134Em6jReFFcq0,688
76
- stoobly_agent/app/cli/scaffold/constants.py,sha256=SMuCd0FwX_C4wENUJU-AxW0KvEsg_1MhQ4GkU287B3Y,1286
76
+ stoobly_agent/app/cli/scaffold/constants.py,sha256=nQiQdE6nd89sQHw4yoHmD6wKEYUDa6Dbxu7b8mu5Oy4,1507
77
77
  stoobly_agent/app/cli/scaffold/docker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
78
  stoobly_agent/app/cli/scaffold/docker/app_builder.py,sha256=IsXZFUumWEBA8NYDFdAohuKmxocoqHqlVFg0-E92QLI,621
79
79
  stoobly_agent/app/cli/scaffold/docker/builder.py,sha256=lNOvDxoLB1L8KSDrvoG4CUuWLAM2egLxwOWeV9Tf8H8,2832
80
- stoobly_agent/app/cli/scaffold/docker/constants.py,sha256=GxHXHC_UzPqSzQ8T5zBu9KtgGVvTWeVUq6gMLzxURg4,276
80
+ stoobly_agent/app/cli/scaffold/docker/constants.py,sha256=bYq2i3iib_YhdE-wtL42qnwPbtfgMSwtfGpT4nFT0fk,394
81
81
  stoobly_agent/app/cli/scaffold/docker/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
82
  stoobly_agent/app/cli/scaffold/docker/service/build_decorator.py,sha256=ZU7z4bkvdS3OK5O4fJhlA9_PNwnFtZW6t7vNF7V5obQ,1003
83
83
  stoobly_agent/app/cli/scaffold/docker/service/builder.py,sha256=jJyC9fpJ0N-s-ALN33WHxzXq5Dwdfoq9enFEAeCwiCc,3221
@@ -85,16 +85,19 @@ stoobly_agent/app/cli/scaffold/docker/service/set_gateway_ports.py,sha256=jvlO5x
85
85
  stoobly_agent/app/cli/scaffold/docker/service/types.py,sha256=qB-yYHlu-PZDc0HYgTUvE5bWNpHxaSThC3JUG8okR1k,88
86
86
  stoobly_agent/app/cli/scaffold/docker/workflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
87
87
  stoobly_agent/app/cli/scaffold/docker/workflow/build_decorator.py,sha256=vbmME0cbN2EnNRlzQ2umj7Y3L7aZT-EHqEpkBFMfe8U,758
88
- stoobly_agent/app/cli/scaffold/docker/workflow/builder.py,sha256=51uGZt9CydBzRwR9aB6uDXuJ2QNm6Iql3AMWv6AtCtw,6919
88
+ stoobly_agent/app/cli/scaffold/docker/workflow/builder.py,sha256=OF0InBOw87tD6pJ-UtVurXHGExBeoez67ramxbAutcE,6864
89
89
  stoobly_agent/app/cli/scaffold/docker/workflow/decorators_factory.py,sha256=Mi6SEFpG2MG9pymPLbPTWBMfosi1ThRAs5DXfjBz4Iw,643
90
- stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py,sha256=AOPupyornoGG3FxP5iSEC9bJ_ErlG7qkilIkVxCmARg,1079
91
- stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py,sha256=WTNiegoWNwz_t3WKu5en0XJjmfHHXvcsa8f4BeS8zvE,2043
90
+ stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py,sha256=D8PgYULERvWLaW1Vn3qspRTuNBoicuP2M1EZnQyvD_M,1080
91
+ stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py,sha256=-nyqU9xyPZIywzef1zOBCElhganLsfjt7G0atKTm1Pw,2042
92
92
  stoobly_agent/app/cli/scaffold/env.py,sha256=e-Ve4p3RUgzFx22B3SIYttvJ_yLuDtA27oDACZ8n-6E,1140
93
+ stoobly_agent/app/cli/scaffold/managed_services_docker_compose.py,sha256=-wLBXUi7DCWsfm5KzZzd_kdJKOTl1NT924XR7dyjbSY,574
93
94
  stoobly_agent/app/cli/scaffold/service.py,sha256=HzYTiQGfReYXEY0Iv4YjGpu5fjCicV61Wst4khmmURs,504
94
- stoobly_agent/app/cli/scaffold/service_command.py,sha256=VtXrgiNO6kD4Oi_alHrJWQhkho3oI-yqs1fe8BPDW6M,1055
95
- stoobly_agent/app/cli/scaffold/service_config.py,sha256=nXopRnHHw6o4Qh1ekYIJCT8hLIMY0QBN4PAXTCL4qFI,5615
95
+ stoobly_agent/app/cli/scaffold/service_command.py,sha256=xqifA0PM9xpXK3TiilplmIrJNR7VG7BO0HrLh74yyZw,1058
96
+ stoobly_agent/app/cli/scaffold/service_config.py,sha256=ev53iZw7Ij1lGYedYelcNFNdtTM6zMmIqofBaFo4gNs,5617
96
97
  stoobly_agent/app/cli/scaffold/service_create_command.py,sha256=bmLGgx9qnh-X_i2_XfdWSQIer0gGkaQx6lXZSIzy-LI,2793
98
+ stoobly_agent/app/cli/scaffold/service_docker_compose.py,sha256=OMUN1-ujQYIZXxDvS4XBf5C9wGalQULkwOiBBQPZbHY,820
97
99
  stoobly_agent/app/cli/scaffold/service_workflow.py,sha256=sQ_Edy_wGHKMXpD0DmhnOWkGEKz7gSgEGNI8f7aXOdg,444
100
+ stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=zvqKmGJ1hVFX0XDEYhvLls2u9twRKhn4jXzWKY-Udvg,9677
98
101
  stoobly_agent/app/cli/scaffold/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
99
102
  stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.context,sha256=1Zm5_ROKZzFMAkMt8dluEJASI2CBi9d9If_Gch9FMNM,193
100
103
  stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.proxy,sha256=JfZOVALEmRE_hVEMIHTmem9Ln32qnfKOAUO1c5Z9fqw,1027
@@ -156,7 +159,7 @@ stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/bin/.snapshot,sha25
156
159
  stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/bin/.stop,sha256=n9k-qnQXfG5J_71FxkteLg962ErT1wTs1juEDtbmUgM,209
157
160
  stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/mock/.docker-compose.mock.yml,sha256=Ba-jNMZUcq62kK_hLpaN7dkEwz3_ZS91aJOOJ8U3Ark,257
158
161
  stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/record/.docker-compose.record.yml,sha256=cbK8vJUnk8llJ6pIE65AxJxD6SSal2ugm5sKjtz3uRY,260
159
- stoobly_agent/app/cli/scaffold/templates/constants.py,sha256=7dlRVpJWUi8ylwUJ-qQg5Hi_Y4fcMXEELaJFj3Ak2sU,1459
162
+ stoobly_agent/app/cli/scaffold/templates/constants.py,sha256=TjuWAZuAbWxS1hZR4jViF1LTBzT8iKLIJE65AvWRKNI,1460
160
163
  stoobly_agent/app/cli/scaffold/templates/factory.py,sha256=zzDMi56w-BWOUOw0DDGgmvrWep_JSqRjp-jQemfQwOo,1759
161
164
  stoobly_agent/app/cli/scaffold/templates/workflow/mock/bin/.configure,sha256=0-fhtg7ZPAEWXqsgFk-W-qvqkHwrSTSI_LNyDMrDytY,102
162
165
  stoobly_agent/app/cli/scaffold/templates/workflow/mock/bin/.init,sha256=5xJbfpwGOmRj5lwK5e0JNlVpNd3WFUkZ0GaCUK40aDk,97
@@ -177,13 +180,16 @@ stoobly_agent/app/cli/scaffold/templates/workflow/test/bin/init,sha256=YxWVVQMEd
177
180
  stoobly_agent/app/cli/scaffold/templates/workflow/test/fixtures/.keep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
178
181
  stoobly_agent/app/cli/scaffold/templates/workflow/test/fixtures.yml,sha256=8DW2LN5WYg1hxmZkqr8o5dxLgDxHtBARFSUiNjz009Y,226
179
182
  stoobly_agent/app/cli/scaffold/templates/workflow/test/lifecycle_hooks.py,sha256=U7mlzT_wBR3uhHSG6CAyt5tBUNAvdIrCw33gdB-F294,467
180
- stoobly_agent/app/cli/scaffold/workflow.py,sha256=5Q0km8-QAylWOUxOtY2D-h0HlDWB8PmtSEYWLA6bLeo,828
183
+ stoobly_agent/app/cli/scaffold/validate_command.py,sha256=k2NCNy3pK7uPKg5wFrVDY1uMA_BDva2DwvGbI6aLWKM,2303
184
+ stoobly_agent/app/cli/scaffold/validate_exceptions.py,sha256=Jtjl4OkbbSRWm0hy7Kf_50zcFh2J324HhNcnwJKH_Oc,54
185
+ stoobly_agent/app/cli/scaffold/workflow.py,sha256=_uur4wdlxZh-piZralqPNoggIkVJ9AICiJVOz4KqKQQ,1421
181
186
  stoobly_agent/app/cli/scaffold/workflow_command.py,sha256=V4Wfv9bgh5MlWAaW_68uudC1wsMcvcTogjZ7mvKDD74,3308
182
187
  stoobly_agent/app/cli/scaffold/workflow_copy_command.py,sha256=R9hh5dWVz7vGld7pENAA_a9gW56EkgG2K35nBQYXwyI,1462
183
188
  stoobly_agent/app/cli/scaffold/workflow_create_command.py,sha256=5xnRYrVb2KlSDARZFjLGGWeURXRu63OHoRLEhO-EAvw,3401
184
189
  stoobly_agent/app/cli/scaffold/workflow_log_command.py,sha256=FN-XyMVnulbassBuqeB21J_PQnOsr_LNs0Dg2tcDkjg,435
185
- stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=AAiUKJ3Wd_Za1_AIKT_F5fvd4RYOMVNFOTNqMGJVbQI,4220
186
- stoobly_agent/app/cli/scaffold_cli.py,sha256=jk2RdQfd46FOPfOZZbz-jNEu-AXG5sauKYmox7arCaA,16586
190
+ stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=DxbcJ-Z7lFobwW9YUp82d2gyRqUk5RzMRmOoMYdX6Eg,4222
191
+ stoobly_agent/app/cli/scaffold/workflow_validate_command.py,sha256=fhHciJXg_u32Wmh8us8LhgQj8D1SxkBADtuBBF4K0FM,4377
192
+ stoobly_agent/app/cli/scaffold_cli.py,sha256=JjmChiUiZ1j_QoJKlvoZ3Hl9YibswRYjjYMhuXHmujU,18053
187
193
  stoobly_agent/app/cli/scenario_cli.py,sha256=3J1EiJOvunkfWrEkOsanw-XrKkOk78ij_GjBlE9p7CE,8229
188
194
  stoobly_agent/app/cli/snapshot_cli.py,sha256=XNxpTm5z3bnBGNGI3_XZIif0ypN62WqYfDmShL5fXg4,9965
189
195
  stoobly_agent/app/cli/trace_cli.py,sha256=K7E-vx3JUcqEDSWOdIOi_AieKNQz7dBfmRrVvKDkzFI,4605
@@ -410,7 +416,7 @@ stoobly_agent/config/constants/statuses.py,sha256=dR88qHHnDR_5ppuKijwc0R24D_fWc6
410
416
  stoobly_agent/config/constants/test_filter.py,sha256=rQ-eMZ8kpq49pqS1PQhaRx59dlRicd-Ag4sjgoXfpY8,109
411
417
  stoobly_agent/config/constants/test_output_level.py,sha256=yrn8cs-lexrK0Ckpc_SX3NhsZPfVhNpmjzjSP62LCro,135
412
418
  stoobly_agent/config/constants/test_strategy.py,sha256=d6-WgKqElB3q_csP-QYFkhR4XvlPGfGdCJ-SBEDEoL4,152
413
- stoobly_agent/config/data_dir.py,sha256=lETERzeXIBYpjoEWRFRZ9NExO1RhdYT0XL4RDELhpP4,7484
419
+ stoobly_agent/config/data_dir.py,sha256=W-J3DPB3ImP6Vir279hC5knw-744vfgjMkKNxG6ZpIY,7712
414
420
  stoobly_agent/config/mitmproxy.py,sha256=z9L1JSWwQFsn4gMZk8Dcz5mOcUc6dYnW1ZugrYTEttw,1902
415
421
  stoobly_agent/config/schema.yml,sha256=b4I8utMrUrMSr86UbXgYYxt2-TJynQA9oQtOQ7CM-PE,1963
416
422
  stoobly_agent/config/settings.yml.sample,sha256=muxP1bWrtknVaSgdseFaw23tuwduILNdQTVy7aB519M,404
@@ -652,6 +658,7 @@ stoobly_agent/test/app/cli/request/request_reset_test.py,sha256=5My6Z452eideAOUu
652
658
  stoobly_agent/test/app/cli/request/request_response_test.py,sha256=Fu-A8tIn016DKme4WIaPzo3YeFY-CPtTOpaSFigUVVM,1263
653
659
  stoobly_agent/test/app/cli/request/request_snapshot_test.py,sha256=0013aoiMZin-2YEtHzEmQspAPA3SUd_6XiItbX0U7Ok,4425
654
660
  stoobly_agent/test/app/cli/request/request_test_test.py,sha256=-cJNXKjgryVVfVt-7IN5fIhBwe3NjFoPmeavDH8lAjU,5527
661
+ stoobly_agent/test/app/cli/scaffold/e2e_test.py,sha256=jDZZk8U9Bj-okZ3mJaosEMzLPlGjAmnepeSIlxFWIx0,16617
655
662
  stoobly_agent/test/app/cli/scenario/scenario_create_test.py,sha256=fGqcjO1_1OvdpUMQfGRVkSyFe61u8WIcp_ndLFrf33A,3962
656
663
  stoobly_agent/test/app/cli/scenario/scenario_replay_integration_test.py,sha256=NbGJzmvPsNLBR0ac65yt_cOTfpnsST1IG7i3F0euwAk,7031
657
664
  stoobly_agent/test/app/cli/scenario/scenario_replay_test.py,sha256=XqR-GDrR8uUtxvukBuIFJ4GsOzBj9WWi4b0VKmfhFyE,6874
@@ -676,7 +683,7 @@ stoobly_agent/test/app/models/factories/resource/local_db/helpers/log_test.py,sh
676
683
  stoobly_agent/test/app/models/factories/resource/local_db/helpers/tiebreak_scenario_request_test.py,sha256=5IFGVGn3ogvRT0fzZgXzhrYlSfSlr8IR1p_XExaegMQ,3399
677
684
  stoobly_agent/test/app/models/factories/resource/local_db/request_adapter_test.py,sha256=Pzq1cBPnP9oSWG-p0c-VoymoHxgp483QmNwmV1b78RA,8453
678
685
  stoobly_agent/test/app/models/factories/resource/local_db/response_adapter_test.py,sha256=9P95EKH5rZGOrmRkRIDlQZqtiLJHk9735og18Ffwpfw,2204
679
- stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=nXE_EpedYoeSULwKIDXj71cxWsQlHoUBnSHHXtcmlyA,5
686
+ stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=6fmB8RVMkjgdY7ZTz7_Hm-ksP2zJXgkVpeXBnzkkylg,5
680
687
  stoobly_agent/test/app/models/schemas/.stoobly/db/stoobly_agent.sqlite3,sha256=ch8gNx6zIelLKQx65gwFx_LRNqUD3EC5xcHZ0ukIQiU,188416
681
688
  stoobly_agent/test/app/models/schemas/.stoobly/settings.yml,sha256=vLwMjweKOdod6tSLtIlyBefPQuNXq9wio4kBaODKtAU,726
682
689
  stoobly_agent/test/app/models/schemas/.stoobly/tmp/options.json,sha256=OTRzarwus48CTrItedXCrgQttJHSEZonEYc7R_knvYg,2212
@@ -708,10 +715,13 @@ stoobly_agent/test/mock_data/petstore-references.yaml,sha256=OpNrCSb5-qKmUBIO9oG
708
715
  stoobly_agent/test/mock_data/petstore-swagger-io.yaml,sha256=FbOEaArZKl1dV7jEf1hyJQv9jdAb5jXfsRRZB5i4-0Y,22094
709
716
  stoobly_agent/test/mock_data/petstore.yaml,sha256=CCdliJky04Az4FIOkFA883uunwFDHLr2Y8ohtozFi_Q,2714
710
717
  stoobly_agent/test/mock_data/request_show_response.py,sha256=K_a0fP0QT58T8sX9PaM6hqtX1A1depZsqg_GsNPf--k,707
718
+ stoobly_agent/test/mock_data/scaffold/docker-compose-assets-service.yml,sha256=ftMKf-iB1Njl5QNatMr1XuBu2KqieLpNgV40_qnW8w8,277
719
+ stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml,sha256=x7hYB1R9RtDDcU1NS1bkhXlTCwCgCPrOW7Y9tyAVUjs,249
720
+ stoobly_agent/test/mock_data/scaffold/index.html,sha256=qJwuYajKZ4ihWZrJQ3BNObV5kf1VGnnm_vqlPJzdqLE,258
711
721
  stoobly_agent/test/mock_data/uspto.yaml,sha256=6U5se7C3o-86J4m9xpOk9Npias399f5CbfWzR87WKwE,7835
712
722
  stoobly_agent/test/test_helper.py,sha256=m_oAI7tmRYCNZdKfNqISWhMv3e44tjeYViQ3nTUfnos,1007
713
- stoobly_agent-1.0.7.dist-info/LICENSE,sha256=8QKGyy45eN76Zk52h8gu1DKX2B_gbWgZ3nzDLofEbaE,548
714
- stoobly_agent-1.0.7.dist-info/METADATA,sha256=X94lZx1QYnVFktZwG09Z2Ca2a2vP8Gt65o_fscFAxKM,3388
715
- stoobly_agent-1.0.7.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
716
- stoobly_agent-1.0.7.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
717
- stoobly_agent-1.0.7.dist-info/RECORD,,
723
+ stoobly_agent-1.0.8.dist-info/LICENSE,sha256=8QKGyy45eN76Zk52h8gu1DKX2B_gbWgZ3nzDLofEbaE,548
724
+ stoobly_agent-1.0.8.dist-info/METADATA,sha256=w_KU9407lw_67FBJdjJGDJ1gnyDrJYPfU-g1OOVFI38,3425
725
+ stoobly_agent-1.0.8.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
726
+ stoobly_agent-1.0.8.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
727
+ stoobly_agent-1.0.8.dist-info/RECORD,,