stoobly-agent 1.0.14__py3-none-any.whl → 1.1.0__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 (24) hide show
  1. stoobly_agent/__init__.py +1 -1
  2. stoobly_agent/app/cli/scaffold/constants.py +7 -1
  3. stoobly_agent/app/cli/scaffold/docker/workflow/builder.py +6 -6
  4. stoobly_agent/app/cli/scaffold/hosts_file_reader.py +65 -0
  5. stoobly_agent/app/cli/scaffold/service_delete_command.py +35 -0
  6. stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py +37 -20
  7. stoobly_agent/app/cli/scaffold/templates/app/.Makefile +19 -1
  8. stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.yml +3 -3
  9. stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/bin/.logs +10 -0
  10. stoobly_agent/app/cli/scaffold/workflow_command.py +1 -5
  11. stoobly_agent/app/cli/scaffold/workflow_log_command.py +30 -5
  12. stoobly_agent/app/cli/scaffold/workflow_run_command.py +0 -1
  13. stoobly_agent/app/cli/scaffold_cli.py +53 -23
  14. stoobly_agent/app/proxy/replay/multipart.py +3 -0
  15. stoobly_agent/test/app/cli/scaffold/cli_invoker.py +134 -0
  16. stoobly_agent/test/app/cli/scaffold/cli_test.py +128 -0
  17. stoobly_agent/test/app/cli/scaffold/e2e_test.py +19 -143
  18. stoobly_agent/test/app/cli/scaffold/hosts_file_reader_test.py +79 -0
  19. stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
  20. {stoobly_agent-1.0.14.dist-info → stoobly_agent-1.1.0.dist-info}/METADATA +9 -10
  21. {stoobly_agent-1.0.14.dist-info → stoobly_agent-1.1.0.dist-info}/RECORD +24 -18
  22. {stoobly_agent-1.0.14.dist-info → stoobly_agent-1.1.0.dist-info}/WHEEL +1 -1
  23. {stoobly_agent-1.0.14.dist-info → stoobly_agent-1.1.0.dist-info}/LICENSE +0 -0
  24. {stoobly_agent-1.0.14.dist-info → stoobly_agent-1.1.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,134 @@
1
+ import pathlib
2
+ import pdb
3
+
4
+ from click.testing import CliRunner
5
+
6
+ from stoobly_agent.app.cli import scaffold
7
+ from stoobly_agent.config.data_dir import DATA_DIR_NAME
8
+
9
+
10
+ class ScaffoldCliInvoker():
11
+
12
+ @staticmethod
13
+ def cli_app_create(runner: CliRunner, app_dir_path: str, app_name: str):
14
+ pathlib.Path(f"{app_dir_path}/{DATA_DIR_NAME}").mkdir(parents=True, exist_ok=True)
15
+
16
+ result = runner.invoke(scaffold, ['app', 'create',
17
+ '--app-dir-path', app_dir_path,
18
+ '--force',
19
+ app_name
20
+ ])
21
+
22
+ assert result.exit_code == 0
23
+ output = result.stdout
24
+ assert not output
25
+
26
+ @staticmethod
27
+ def cli_app_mkcert(runner: CliRunner, app_dir_path: str):
28
+ result = runner.invoke(scaffold, ['app', 'mkcert',
29
+ '--app-dir-path', app_dir_path,
30
+ '--context-dir-path', app_dir_path,
31
+ ])
32
+
33
+ assert result.exit_code == 0
34
+ output = result.stdout
35
+ assert not output
36
+
37
+ @staticmethod
38
+ def cli_service_create(runner: CliRunner, app_dir_path: str, hostname: str, service_name: str, https: bool):
39
+ scheme = 'http'
40
+ port = '80'
41
+ if https == True:
42
+ scheme = 'https'
43
+ port = '443'
44
+
45
+ result = runner.invoke(scaffold, ['service', 'create',
46
+ '--app-dir-path', app_dir_path,
47
+ '--env', 'TEST',
48
+ '--force',
49
+ '--hostname', hostname,
50
+ '--scheme', scheme,
51
+ '--port', port,
52
+ '--workflow', 'mock',
53
+ '--workflow', 'record',
54
+ '--workflow', 'test',
55
+ service_name
56
+ ])
57
+ assert result.exit_code == 0
58
+ output = result.stdout
59
+ assert not output
60
+
61
+ # Specific flags for assets
62
+ @staticmethod
63
+ def cli_service_create_assets(runner: CliRunner, app_dir_path: str, hostname: str, service_name: str, https: bool):
64
+ scheme = 'http'
65
+ port = '80'
66
+ if https == True:
67
+ scheme = 'https'
68
+ port = '443'
69
+ proxy_mode_reverse_spec = f"reverse:{scheme}://{hostname}:8080"
70
+
71
+ result = runner.invoke(scaffold, ['service', 'create',
72
+ '--app-dir-path', app_dir_path,
73
+ '--force',
74
+ '--hostname', hostname,
75
+ '--scheme', scheme,
76
+ '--port', port,
77
+ '--proxy-mode', proxy_mode_reverse_spec,
78
+ '--detached',
79
+ '--workflow', 'test',
80
+ service_name
81
+ ])
82
+ assert result.exit_code == 0
83
+ output = result.stdout
84
+ assert not output
85
+
86
+ @staticmethod
87
+ def cli_service_delete(runner: CliRunner, app_dir_path: str, service_name: str):
88
+ result = runner.invoke(scaffold, ['service', 'delete',
89
+ '--app-dir-path', app_dir_path,
90
+ service_name
91
+ ])
92
+ assert result.exit_code == 0
93
+ output = result.stdout
94
+ assert 'error' not in output.lower()
95
+
96
+ @staticmethod
97
+ def cli_workflow_create(runner: CliRunner, app_dir_path: str, service_name: str):
98
+ result = runner.invoke(scaffold, ['workflow', 'create',
99
+ '--app-dir-path', app_dir_path,
100
+ '--service', service_name,
101
+ '--template', 'mock',
102
+ 'ci',
103
+ ])
104
+
105
+ assert result.exit_code == 0
106
+ output = result.stdout
107
+ assert not output
108
+
109
+ @staticmethod
110
+ def cli_workflow_run(runner: CliRunner, app_dir_path: str, target_workflow_name: str):
111
+ command = ['workflow', 'run',
112
+ '--app-dir-path', app_dir_path,
113
+ '--context-dir-path', app_dir_path,
114
+ target_workflow_name,
115
+ ]
116
+ result = runner.invoke(scaffold, command)
117
+
118
+ assert result.exit_code == 0
119
+ output = result.stdout
120
+ assert output
121
+
122
+ @staticmethod
123
+ def cli_workflow_stop(runner: CliRunner, app_dir_path: str, target_workflow_name: str):
124
+ command = ['workflow', 'stop',
125
+ '--app-dir-path', app_dir_path,
126
+ '--context-dir-path', app_dir_path,
127
+ target_workflow_name,
128
+ ]
129
+ result = runner.invoke(scaffold, command)
130
+
131
+ assert result.exit_code == 0
132
+ output = result.stdout
133
+ assert output
134
+
@@ -0,0 +1,128 @@
1
+ import os
2
+ import pdb
3
+ import shutil
4
+
5
+ from click.testing import CliRunner
6
+ import pytest
7
+
8
+ from stoobly_agent.app.cli.scaffold.app import App
9
+ from stoobly_agent.app.cli.scaffold.constants import (
10
+ DOCKER_NAMESPACE,
11
+ WORKFLOW_RECORD_TYPE,
12
+ )
13
+ from stoobly_agent.app.cli.scaffold.service_docker_compose import ServiceDockerCompose
14
+ from stoobly_agent.config.data_dir import DataDir
15
+ from stoobly_agent.test.app.cli.scaffold.e2e_test import ScaffoldCliInvoker
16
+ from stoobly_agent.test.test_helper import reset
17
+
18
+
19
+ class TestScaffoldCli():
20
+
21
+ @pytest.fixture(scope='module', autouse=True)
22
+ def settings(self):
23
+ return reset()
24
+
25
+ @pytest.fixture(scope='module')
26
+ def runner(self):
27
+ yield CliRunner()
28
+
29
+ @pytest.fixture(scope='class')
30
+ def app_name(self):
31
+ yield "0.0.1"
32
+
33
+ @pytest.fixture(scope='class', autouse=True)
34
+ def temp_dir(self):
35
+ data_dir_path = DataDir.instance().path
36
+ tmp_path = data_dir_path[:data_dir_path.rfind('/')]
37
+
38
+ yield tmp_path
39
+
40
+ @pytest.fixture(scope='class', autouse=True)
41
+ def app_dir_path(self, temp_dir, app_name):
42
+ yield temp_dir
43
+
44
+ @pytest.fixture(scope='class')
45
+ def hostname(self):
46
+ yield "http.badssl.com"
47
+
48
+ @pytest.fixture(scope='class')
49
+ def https_service_hostname(self):
50
+ yield "example.com"
51
+
52
+ @pytest.fixture(scope='class')
53
+ def external_service_name(self):
54
+ yield "external-service"
55
+
56
+ @pytest.fixture(scope='class')
57
+ def external_https_service_name(self):
58
+ yield "external-https-service"
59
+
60
+ class TestServiceDelete():
61
+ @pytest.fixture(scope='class', autouse=True)
62
+ def target_workflow_name(self):
63
+ yield WORKFLOW_RECORD_TYPE
64
+
65
+ @pytest.fixture(scope='class')
66
+ def external_service_docker_compose(self, app_dir_path, target_workflow_name, external_service_name, hostname):
67
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=external_service_name, hostname=hostname)
68
+
69
+ @pytest.fixture(scope='class')
70
+ def external_https_service_docker_compose(self, app_dir_path, target_workflow_name, external_https_service_name, https_service_hostname):
71
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=external_https_service_name, hostname=https_service_hostname)
72
+
73
+ @pytest.fixture(scope="class", autouse=True)
74
+ def create_setup(self, runner, app_dir_path, app_name, external_service_docker_compose, external_https_service_docker_compose):
75
+
76
+ ScaffoldCliInvoker.cli_app_create(runner, app_dir_path, app_name)
77
+
78
+ # Create external user defined services
79
+ ScaffoldCliInvoker.cli_service_create(runner, app_dir_path, external_service_docker_compose.hostname, external_service_docker_compose.service_name, False)
80
+ ScaffoldCliInvoker.cli_service_create(runner, app_dir_path, external_https_service_docker_compose.hostname, external_https_service_docker_compose.service_name, True)
81
+
82
+ # Generate certs
83
+ ScaffoldCliInvoker.cli_app_mkcert(runner, app_dir_path)
84
+
85
+ @pytest.fixture(scope="class", autouse=True)
86
+ def cleanup_after_all(self, runner, app_dir_path, target_workflow_name):
87
+ yield
88
+ ScaffoldCliInvoker.cli_workflow_stop(runner, app_dir_path, target_workflow_name)
89
+ shutil.rmtree(app_dir_path)
90
+
91
+
92
+ def test_service_delete(self, runner, app_dir_path, external_service_docker_compose):
93
+ app = App(app_dir_path, DOCKER_NAMESPACE)
94
+ service_name = external_service_docker_compose.service_name
95
+
96
+ ScaffoldCliInvoker.cli_service_delete(runner, app_dir_path, service_name)
97
+
98
+ found = False
99
+ service_paths = app.service_paths
100
+ for service_path in service_paths:
101
+ if service_name in service_path:
102
+ found = True
103
+ break
104
+ if found:
105
+ assert False
106
+
107
+ def test_service_delete_https(self, runner, app_dir_path, external_https_service_docker_compose):
108
+ app = App(app_dir_path, DOCKER_NAMESPACE)
109
+ service_name = external_https_service_docker_compose.service_name
110
+ hostname = external_https_service_docker_compose.hostname
111
+
112
+ ScaffoldCliInvoker.cli_service_delete(runner, app_dir_path, service_name)
113
+
114
+ found = False
115
+ service_paths = app.service_paths
116
+ for service_path in service_paths:
117
+ if service_name in service_path:
118
+ found = True
119
+ break
120
+ if found:
121
+ assert False
122
+
123
+ # Certs should be deleted
124
+ certs_dir_path = os.listdir(app.certs_dir_path)
125
+ for cert_file in certs_dir_path:
126
+ if hostname in cert_file:
127
+ assert False
128
+
@@ -1,19 +1,16 @@
1
1
  from pathlib import Path
2
- import pathlib
3
2
  import pdb
4
3
  import shutil
5
4
 
6
5
  from click.testing import CliRunner
7
- import docker
8
6
  import pytest
9
7
 
10
- from stoobly_agent.app.cli import scaffold
11
8
  from stoobly_agent.app.cli.scaffold.app import App
12
9
  from stoobly_agent.app.cli.scaffold.constants import (
10
+ DOCKER_NAMESPACE,
13
11
  WORKFLOW_RECORD_TYPE,
14
12
  WORKFLOW_TEST_TYPE,
15
13
  )
16
- from stoobly_agent.app.cli.scaffold.constants import DOCKER_NAMESPACE
17
14
  from stoobly_agent.app.cli.scaffold.managed_services_docker_compose import (
18
15
  ManagedServicesDockerCompose,
19
16
  )
@@ -24,7 +21,8 @@ from stoobly_agent.app.cli.scaffold.service_workflow_validate_command import (
24
21
  from stoobly_agent.app.cli.scaffold.workflow_validate_command import (
25
22
  WorkflowValidateCommand,
26
23
  )
27
- from stoobly_agent.config.data_dir import DATA_DIR_NAME, DataDir
24
+ from stoobly_agent.config.data_dir import DataDir
25
+ from stoobly_agent.test.app.cli.scaffold.cli_invoker import ScaffoldCliInvoker
28
26
  from stoobly_agent.test.test_helper import reset
29
27
 
30
28
 
@@ -39,10 +37,6 @@ class TestScaffoldE2e():
39
37
  def runner(self):
40
38
  yield CliRunner()
41
39
 
42
- @pytest.fixture(scope='class')
43
- def docker_client(self):
44
- yield docker.from_env()
45
-
46
40
  @pytest.fixture(scope='class')
47
41
  def app_name(self):
48
42
  yield "0.0.1"
@@ -113,22 +107,16 @@ class TestScaffoldE2e():
113
107
  def local_service_docker_compose(self, app_dir_path, target_workflow_name, local_service_name, local_hostname):
114
108
  yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=local_service_name, hostname=local_hostname)
115
109
 
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
110
  @pytest.fixture(scope="class", autouse=True)
123
111
  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)
112
+ ScaffoldCliInvoker.cli_app_create(runner, app_dir_path, app_name)
125
113
 
126
114
  # 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)
115
+ ScaffoldCliInvoker.cli_service_create(runner, app_dir_path, external_service_docker_compose.hostname, external_service_docker_compose.service_name, False)
116
+ ScaffoldCliInvoker.cli_service_create(runner, app_dir_path, external_https_service_docker_compose.hostname, external_https_service_docker_compose.service_name, True)
129
117
 
130
118
  # 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)
119
+ ScaffoldCliInvoker.cli_service_create(runner, app_dir_path, local_service_docker_compose.hostname, local_service_docker_compose.service_name, False)
132
120
 
133
121
  # Validate docker-compose path exists
134
122
  destination_path = Path(local_service_docker_compose.docker_compose_path)
@@ -139,14 +127,15 @@ class TestScaffoldE2e():
139
127
  # Record workflow doesn't have a fixtures folder
140
128
 
141
129
  # Generate certs
142
- TestScaffoldE2e.cli_app_mkcert(runner, app_dir_path)
130
+ ScaffoldCliInvoker.cli_app_mkcert(runner, app_dir_path)
143
131
 
144
- TestScaffoldE2e.cli_workflow_run(runner, app_dir_path, target_workflow_name)
132
+ ScaffoldCliInvoker.cli_workflow_run(runner, app_dir_path, target_workflow_name)
145
133
 
146
134
  @pytest.fixture(scope="class", autouse=True)
147
135
  def cleanup_after_all(self, runner, app_dir_path, target_workflow_name):
148
136
  yield
149
- TestScaffoldE2e.cli_workflow_stop(runner, app_dir_path, target_workflow_name)
137
+ ScaffoldCliInvoker.cli_workflow_stop(runner, app_dir_path, target_workflow_name)
138
+ shutil.rmtree(app_dir_path)
150
139
 
151
140
  def test_core_components(self, app_dir_path, target_workflow_name):
152
141
  app = App(app_dir_path, DOCKER_NAMESPACE)
@@ -228,13 +217,13 @@ class TestScaffoldE2e():
228
217
  @pytest.fixture(scope="class", autouse=True)
229
218
  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
219
 
231
- TestScaffoldE2e.cli_app_create(runner, app_dir_path, app_name)
220
+ ScaffoldCliInvoker.cli_app_create(runner, app_dir_path, app_name)
232
221
 
233
222
  # 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)
223
+ ScaffoldCliInvoker.cli_service_create(runner, app_dir_path, external_service_docker_compose.hostname, external_service_docker_compose.service_name, False)
235
224
  # 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)
225
+ ScaffoldCliInvoker.cli_service_create(runner, app_dir_path, local_service_docker_compose.hostname, local_service_docker_compose.service_name, False)
226
+ ScaffoldCliInvoker.cli_service_create_assets(runner, app_dir_path, assets_service_docker_compose.hostname, assets_service_docker_compose.service_name, False)
238
227
 
239
228
  # Don't run the local user defined service in the 'test' workflow
240
229
  # So don't copy the Docker Compose file over
@@ -244,7 +233,7 @@ class TestScaffoldE2e():
244
233
  assert destination_path.is_file()
245
234
  shutil.copyfile(assets_service_mock_docker_compose_path, destination_path)
246
235
 
247
- TestScaffoldE2e.cli_service_create_assets(runner, app_dir_path, assets_service_docker_compose.hostname, assets_service_docker_compose.service_name, False)
236
+ ScaffoldCliInvoker.cli_service_create_assets(runner, app_dir_path, assets_service_docker_compose.hostname, assets_service_docker_compose.service_name, False)
248
237
 
249
238
  # Add assets for assets service
250
239
  data_dir_path = DataDir.instance().path
@@ -263,12 +252,13 @@ class TestScaffoldE2e():
263
252
  with open(f"{command.fixtures_dir_path}/shared_file.txt", 'w') as file:
264
253
  file.write('this is a shared file')
265
254
 
266
- TestScaffoldE2e.cli_workflow_run(runner, app_dir_path, target_workflow_name=target_workflow_name)
255
+ ScaffoldCliInvoker.cli_workflow_run(runner, app_dir_path, target_workflow_name=target_workflow_name)
267
256
 
268
257
  @pytest.fixture(scope="class", autouse=True)
269
258
  def cleanup_after_all(self, runner, app_dir_path, target_workflow_name):
270
259
  yield
271
- TestScaffoldE2e.cli_workflow_stop(runner, app_dir_path, target_workflow_name)
260
+ ScaffoldCliInvoker.cli_workflow_stop(runner, app_dir_path, target_workflow_name)
261
+ shutil.rmtree(app_dir_path)
272
262
 
273
263
  def test_no_core_components(self, app_dir_path, target_workflow_name):
274
264
  app = App(app_dir_path, DOCKER_NAMESPACE)
@@ -312,117 +302,3 @@ class TestScaffoldE2e():
312
302
  command = ServiceWorkflowValidateCommand(app, **config)
313
303
  command.validate()
314
304
 
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
-
@@ -0,0 +1,79 @@
1
+ import pdb
2
+ import pytest
3
+
4
+ from stoobly_agent.app.cli.scaffold.hosts_file_reader import HostsFileReader
5
+
6
+
7
+ class TestHostsFileReader():
8
+
9
+ @pytest.fixture
10
+ def hosts_file_reader(self):
11
+ yield HostsFileReader()
12
+
13
+ def test_get_hosts_file_path(self, hosts_file_reader):
14
+ hosts_file_path = hosts_file_reader._HostsFileReader__get_hosts_file_path()
15
+
16
+ # Test runners are all Linux distros for now
17
+ assert hosts_file_path == '/etc/hosts'
18
+
19
+ def test_get_hosts(self, hosts_file_reader):
20
+ hosts = hosts_file_reader.get_hosts()
21
+
22
+ assert hosts
23
+ assert len(hosts) > 1
24
+
25
+ localhost_found = False
26
+ for host in hosts:
27
+ if host.ip_address == '127.0.0.1' and 'localhost' in host.hostnames:
28
+ localhost_found = True
29
+ break
30
+ assert localhost_found
31
+
32
+ def test_find_host(self, hosts_file_reader):
33
+ url = 'localhost'
34
+
35
+ host = hosts_file_reader.find_host(url)
36
+
37
+ assert host
38
+ assert host.ip_address == '127.0.0.1'
39
+ assert 'localhost' in host.hostnames
40
+
41
+
42
+ class TestsSplitHostsLine():
43
+ def test_basic(self, hosts_file_reader):
44
+ line = '0.0.0.0 example.com'
45
+ split = hosts_file_reader._HostsFileReader__split_hosts_line(line)
46
+
47
+ assert split[0] == '0.0.0.0'
48
+ assert split[1] == 'example.com'
49
+
50
+ def test_tabs(self, hosts_file_reader):
51
+ line = '0.0.0.0\texample.com'
52
+ split = hosts_file_reader._HostsFileReader__split_hosts_line(line)
53
+
54
+ assert split[0] == '0.0.0.0'
55
+ assert split[1] == 'example.com'
56
+
57
+ def test_comment(self, hosts_file_reader):
58
+ line = '# 0.0.0.0 example.com'
59
+ split = hosts_file_reader._HostsFileReader__split_hosts_line(line)
60
+
61
+ assert len(split) == 0
62
+
63
+ def test_inline_comment(self, hosts_file_reader):
64
+ line = '0.0.0.0\texample.com # Comment'
65
+ split = hosts_file_reader._HostsFileReader__split_hosts_line(line)
66
+
67
+ assert split[0] == '0.0.0.0'
68
+ assert split[1] == 'example.com'
69
+
70
+ def test_multiple_hostnames(self, hosts_file_reader):
71
+ line = '0.0.0.0\texample.com example2.com example3.com # Comment'
72
+ split = hosts_file_reader._HostsFileReader__split_hosts_line(line)
73
+
74
+ assert split[0] == '0.0.0.0'
75
+ assert split[1] == 'example.com'
76
+ assert split[2] == 'example2.com'
77
+ assert split[3] == 'example3.com'
78
+
79
+
@@ -1 +1 @@
1
- 1.0.7
1
+ 1.0.14
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: stoobly-agent
3
- Version: 1.0.14
3
+ Version: 1.1.0
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
@@ -13,24 +13,23 @@ Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Programming Language :: Python :: 3.13
15
15
  Requires-Dist: click (>=8.1.0,<9.0.0)
16
- Requires-Dist: diff-match-patch (>=20230430,<20230431)
17
- Requires-Dist: distro (>=1.6.0,<1.7.0)
18
- Requires-Dist: dnspython (>=2.6.1,<2.7.0)
16
+ Requires-Dist: diff-match-patch (>=v20241021,<20241022)
17
+ Requires-Dist: distro (>=1.9.0,<1.10)
18
+ Requires-Dist: dnspython (>=2.7.0,<2.8)
19
19
  Requires-Dist: docker (>=7.1.0,<8.0)
20
20
  Requires-Dist: httptools (>=0.4.0)
21
21
  Requires-Dist: jmespath (>=1.0.0)
22
- Requires-Dist: mergedeep (>=1.3.0,<1.3.4)
23
- Requires-Dist: mitmproxy (>=10.0.0,<11.0.0)
24
- Requires-Dist: multipart (>=0.2.5,<0.3.0)
22
+ Requires-Dist: mergedeep (>=1.3,<1.4)
23
+ Requires-Dist: mitmproxy (>=11.0.2,<11.1.0)
24
+ Requires-Dist: multipart (>=1.2.1,<1.3)
25
25
  Requires-Dist: openapi-core (>=0.19.0,<0.20.0)
26
26
  Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
27
27
  Requires-Dist: pyyaml (>=6.0.1)
28
28
  Requires-Dist: requests (>=2.31.0)
29
29
  Requires-Dist: stoobly_orator (>=0.9.12)
30
30
  Requires-Dist: tabulate (>=0.8.8)
31
- Requires-Dist: watchdog (>=2.1.0,<=2.1.3)
32
- Requires-Dist: werkzeug (<3.0.0)
33
- Requires-Dist: yamale (>=4.0.0,<=4.0.2)
31
+ Requires-Dist: watchdog (>=6.0.0,<=6.1.0)
32
+ Requires-Dist: yamale (>=6.0.0,<=7.0.0)
34
33
  Project-URL: Homepage, https://github.com/Stoobly/stoobly-agent
35
34
  Description-Content-Type: text/markdown
36
35