devdox-ai-locust 0.1.3.post1__tar.gz → 0.1.4__tar.gz
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.
Potentially problematic release.
This version of devdox-ai-locust might be problematic. Click here for more details.
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/PKG-INFO +26 -11
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/README.md +25 -10
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/pyproject.toml +2 -2
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/cli.py +19 -3
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/config.py +1 -1
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/hybrid_loctus_generator.py +37 -8
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/locust_generator.py +84 -9
- devdox_ai_locust-0.1.4/src/devdox_ai_locust/prompt/test_data.j2 +186 -0
- devdox_ai_locust-0.1.4/src/devdox_ai_locust/prompt/workflow.j2 +483 -0
- devdox_ai_locust-0.1.4/src/devdox_ai_locust/templates/mongo/data_provider.py.j2 +303 -0
- devdox_ai_locust-0.1.4/src/devdox_ai_locust/templates/mongo/db_config.py.j2 +271 -0
- devdox_ai_locust-0.1.4/src/devdox_ai_locust/templates/mongo/db_integration.j2 +352 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/templates/readme.md.j2 +3 -1
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/templates/requirement.txt.j2 +5 -2
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/templates/test_data.py.j2 +5 -1
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust.egg-info/PKG-INFO +26 -11
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust.egg-info/SOURCES.txt +3 -1
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/tests/test_cli.py +3 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/tests/test_config.py +4 -4
- devdox_ai_locust-0.1.3.post1/src/devdox_ai_locust/prompt/test_data.j2 +0 -62
- devdox_ai_locust-0.1.3.post1/src/devdox_ai_locust/prompt/workflow.j2 +0 -145
- devdox_ai_locust-0.1.3.post1/tests/test_data.py +0 -505
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/LICENSE +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/setup.cfg +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/__init__.py +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/prompt/domain.j2 +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/prompt/locust.j2 +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/prompt/validation.j2 +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/py.typed +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/schemas/__init__.py +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/schemas/processing_result.py +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/templates/base_workflow.py.j2 +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/templates/config.py.j2 +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/templates/custom_flows.py.j2 +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/templates/endpoint_template.py.j2 +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/templates/env.example.j2 +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/templates/fallback_locust.py.j2 +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/templates/locust.py.j2 +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/templates/utils.py.j2 +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/utils/__init__.py +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/utils/file_creation.py +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/utils/open_ai_parser.py +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/utils/swagger_utils.py +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust.egg-info/dependency_links.txt +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust.egg-info/entry_points.txt +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust.egg-info/requires.txt +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust.egg-info/top_level.txt +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/tests/test_hybrid_loctus_generator.py +0 -0
- {devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/tests/test_locust_generator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devdox_ai_locust
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: AI-powered Locust load test generator from API documentation
|
|
5
5
|
Author-email: Hayat Bourji <hayat.bourgi@montyholding.com>
|
|
6
6
|
Maintainer-email: Hayat Bourji <hayat.bourgi@montyholding.com>
|
|
@@ -73,19 +73,27 @@ Dynamic: license-file
|
|
|
73
73
|
DevDox AI Locust automatically generates comprehensive Locust load testing scripts from your API documentation (OpenAPI/Swagger specs). Using advanced AI capabilities, it creates realistic test scenarios, handles complex authentication flows, and generates production-ready performance tests.
|
|
74
74
|
|
|
75
75
|
|
|
76
|
-
## 🆕 What's New in 0.1.
|
|
76
|
+
## 🆕 What's New in 0.1.4
|
|
77
77
|
|
|
78
|
-
###
|
|
78
|
+
### MongoDB Integration
|
|
79
79
|
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
80
|
+
- Added a new data provider class: MongoDataProvider
|
|
81
|
+
- Connects Locust test data generation directly to MongoDB
|
|
82
|
+
- Enables realistic test data retrieval for entities like users, products, orders, affiliates, etc.
|
|
83
|
+
- Supports **real data** from the database and **synthetic fallback generation** when MongoDB is disabled or unavailable
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
#### 2. **New MongoDataProvider Methods**
|
|
86
|
+
| Method | Description |
|
|
87
|
+
|----------------------------------------------------------|--------------|
|
|
88
|
+
| `get_document(collection_name)` | Retrieves a single realistic document from MongoDB or fallback generator |
|
|
89
|
+
| `get_multiple_documents(collection_name, count=10, query=None)` | Retrieves multiple documents or generates them in batches |
|
|
90
|
+
| `clear_cache()` | Clears in-memory cached data for all collections |
|
|
91
|
+
| `get_stats()` | Returns usage and cache statistics for debugging and optimization |
|
|
92
|
+
|
|
93
|
+
#### 3. **Smart Fallbacks**
|
|
94
|
+
If MongoDB is disabled (`enable_mongodb = false` in `db_config.py`),
|
|
95
|
+
the system automatically switches to **synthetic data generation** using the LLM-based `TestDataGenerator`.
|
|
86
96
|
|
|
87
|
-
- Fixed edge cases in code block extraction where malformed responses could cause generation failures
|
|
88
|
-
- Improved retry logic to handle transient API errors without interrupting the generation process
|
|
89
97
|
|
|
90
98
|
## ✨ Features
|
|
91
99
|
|
|
@@ -139,14 +147,21 @@ devdox_ai_locust generate --openapi-url https://api.example.com/openapi.json --o
|
|
|
139
147
|
|
|
140
148
|
# Generate with custom configuration
|
|
141
149
|
devdox_ai_locust generate \
|
|
142
|
-
https://
|
|
150
|
+
https://petstore3.swagger.io/api/v3/openapi.json \
|
|
143
151
|
--output ./petstore-tests \
|
|
144
152
|
--together-api-key your_api_key \
|
|
145
153
|
|
|
154
|
+
# Generate with db integration
|
|
155
|
+
devdox_ai_locust generate \
|
|
156
|
+
https://petstore3.swagger.io/api/v3/openapi.json \
|
|
157
|
+
--output ./petstore-tests \
|
|
158
|
+
--db-type mongo \
|
|
146
159
|
```
|
|
147
160
|
|
|
148
161
|
|
|
149
162
|
|
|
163
|
+
|
|
164
|
+
|
|
150
165
|
## 📖 Documentation
|
|
151
166
|
|
|
152
167
|
### Command Line Interface
|
|
@@ -9,19 +9,27 @@
|
|
|
9
9
|
DevDox AI Locust automatically generates comprehensive Locust load testing scripts from your API documentation (OpenAPI/Swagger specs). Using advanced AI capabilities, it creates realistic test scenarios, handles complex authentication flows, and generates production-ready performance tests.
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
## 🆕 What's New in 0.1.
|
|
12
|
+
## 🆕 What's New in 0.1.4
|
|
13
13
|
|
|
14
|
-
###
|
|
14
|
+
### MongoDB Integration
|
|
15
15
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
16
|
+
- Added a new data provider class: MongoDataProvider
|
|
17
|
+
- Connects Locust test data generation directly to MongoDB
|
|
18
|
+
- Enables realistic test data retrieval for entities like users, products, orders, affiliates, etc.
|
|
19
|
+
- Supports **real data** from the database and **synthetic fallback generation** when MongoDB is disabled or unavailable
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
#### 2. **New MongoDataProvider Methods**
|
|
22
|
+
| Method | Description |
|
|
23
|
+
|----------------------------------------------------------|--------------|
|
|
24
|
+
| `get_document(collection_name)` | Retrieves a single realistic document from MongoDB or fallback generator |
|
|
25
|
+
| `get_multiple_documents(collection_name, count=10, query=None)` | Retrieves multiple documents or generates them in batches |
|
|
26
|
+
| `clear_cache()` | Clears in-memory cached data for all collections |
|
|
27
|
+
| `get_stats()` | Returns usage and cache statistics for debugging and optimization |
|
|
28
|
+
|
|
29
|
+
#### 3. **Smart Fallbacks**
|
|
30
|
+
If MongoDB is disabled (`enable_mongodb = false` in `db_config.py`),
|
|
31
|
+
the system automatically switches to **synthetic data generation** using the LLM-based `TestDataGenerator`.
|
|
22
32
|
|
|
23
|
-
- Fixed edge cases in code block extraction where malformed responses could cause generation failures
|
|
24
|
-
- Improved retry logic to handle transient API errors without interrupting the generation process
|
|
25
33
|
|
|
26
34
|
## ✨ Features
|
|
27
35
|
|
|
@@ -75,14 +83,21 @@ devdox_ai_locust generate --openapi-url https://api.example.com/openapi.json --o
|
|
|
75
83
|
|
|
76
84
|
# Generate with custom configuration
|
|
77
85
|
devdox_ai_locust generate \
|
|
78
|
-
https://
|
|
86
|
+
https://petstore3.swagger.io/api/v3/openapi.json \
|
|
79
87
|
--output ./petstore-tests \
|
|
80
88
|
--together-api-key your_api_key \
|
|
81
89
|
|
|
90
|
+
# Generate with db integration
|
|
91
|
+
devdox_ai_locust generate \
|
|
92
|
+
https://petstore3.swagger.io/api/v3/openapi.json \
|
|
93
|
+
--output ./petstore-tests \
|
|
94
|
+
--db-type mongo \
|
|
82
95
|
```
|
|
83
96
|
|
|
84
97
|
|
|
85
98
|
|
|
99
|
+
|
|
100
|
+
|
|
86
101
|
## 📖 Documentation
|
|
87
102
|
|
|
88
103
|
### Command Line Interface
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "devdox_ai_locust"
|
|
8
|
-
version = "0.1.
|
|
8
|
+
version = "0.1.4"
|
|
9
9
|
description = "AI-powered Locust load test generator from API documentation"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
license = {text = "Apache-2.0" }
|
|
@@ -101,7 +101,7 @@ exclude = ["tests*"]
|
|
|
101
101
|
|
|
102
102
|
|
|
103
103
|
[tool.setuptools.package-data]
|
|
104
|
-
devdox_ai_locust = ["schemas/*.json", "templates/*.j2","prompt/*.j2", "py.typed","*.j2"]
|
|
104
|
+
devdox_ai_locust = ["schemas/*.json", "templates/*.j2","templates/mongo/*","prompt/*.j2", "py.typed","*.j2"]
|
|
105
105
|
|
|
106
106
|
# flake8 configuration (legacy - remove if using ruff)
|
|
107
107
|
[tool.flake8]
|
|
@@ -197,19 +197,20 @@ async def _generate_and_create_tests(
|
|
|
197
197
|
custom_requirement: Optional[str] = "",
|
|
198
198
|
host: Optional[str] = "0.0.0.0",
|
|
199
199
|
auth: bool = False,
|
|
200
|
+
db_type: str = "",
|
|
200
201
|
) -> List[Dict[Any, Any]]:
|
|
201
202
|
"""Generate tests using AI and create test files"""
|
|
202
203
|
together_client = AsyncTogether(api_key=api_key)
|
|
203
204
|
|
|
204
205
|
with console.status("[bold green]Generating Locust tests with AI..."):
|
|
205
206
|
generator = HybridLocustGenerator(ai_client=together_client)
|
|
206
|
-
|
|
207
207
|
test_files, test_directories = await generator.generate_from_endpoints(
|
|
208
208
|
endpoints=endpoints,
|
|
209
209
|
api_info=api_info,
|
|
210
210
|
custom_requirement=custom_requirement,
|
|
211
211
|
target_host=host,
|
|
212
212
|
include_auth=auth,
|
|
213
|
+
db_type=db_type,
|
|
213
214
|
)
|
|
214
215
|
|
|
215
216
|
# Create test files
|
|
@@ -271,6 +272,12 @@ def cli(ctx: click.Context, verbose: bool) -> None:
|
|
|
271
272
|
)
|
|
272
273
|
@click.option("--host", "-H", type=str, help="Target host URL")
|
|
273
274
|
@click.option("--auth/--no-auth", default=True, help="Include authentication in tests")
|
|
275
|
+
@click.option(
|
|
276
|
+
"--db-type",
|
|
277
|
+
type=click.Choice(["", "mongo", "postgresql"], case_sensitive=False),
|
|
278
|
+
default="",
|
|
279
|
+
help="Database type for testing (empty for no database, mongo, or postgresql)",
|
|
280
|
+
)
|
|
274
281
|
@click.option("--dry-run", is_flag=True, help="Generate tests without running them")
|
|
275
282
|
@click.option(
|
|
276
283
|
"--custom-requirement", type=str, help="Custom requirements for test generation"
|
|
@@ -291,6 +298,7 @@ def generate(
|
|
|
291
298
|
run_time: str,
|
|
292
299
|
host: Optional[str],
|
|
293
300
|
auth: bool,
|
|
301
|
+
db_type: str,
|
|
294
302
|
dry_run: bool,
|
|
295
303
|
custom_requirement: Optional[str],
|
|
296
304
|
together_api_key: Optional[str],
|
|
@@ -309,6 +317,7 @@ def generate(
|
|
|
309
317
|
run_time,
|
|
310
318
|
host,
|
|
311
319
|
auth,
|
|
320
|
+
db_type,
|
|
312
321
|
dry_run,
|
|
313
322
|
custom_requirement,
|
|
314
323
|
together_api_key,
|
|
@@ -332,6 +341,7 @@ async def _async_generate(
|
|
|
332
341
|
run_time: str,
|
|
333
342
|
host: Optional[str],
|
|
334
343
|
auth: bool,
|
|
344
|
+
db_type: str,
|
|
335
345
|
dry_run: bool,
|
|
336
346
|
custom_requirement: Optional[str],
|
|
337
347
|
together_api_key: Optional[str],
|
|
@@ -343,7 +353,6 @@ async def _async_generate(
|
|
|
343
353
|
try:
|
|
344
354
|
_, api_key = _initialize_config(together_api_key)
|
|
345
355
|
output_dir = _setup_output_directory(output)
|
|
346
|
-
|
|
347
356
|
# Display configuration
|
|
348
357
|
if ctx.obj["verbose"]:
|
|
349
358
|
_display_configuration(
|
|
@@ -363,7 +372,14 @@ async def _async_generate(
|
|
|
363
372
|
)
|
|
364
373
|
|
|
365
374
|
created_files = await _generate_and_create_tests(
|
|
366
|
-
api_key,
|
|
375
|
+
api_key,
|
|
376
|
+
endpoints,
|
|
377
|
+
api_info,
|
|
378
|
+
output_dir,
|
|
379
|
+
custom_requirement,
|
|
380
|
+
host,
|
|
381
|
+
auth,
|
|
382
|
+
db_type,
|
|
367
383
|
)
|
|
368
384
|
|
|
369
385
|
# Show results
|
|
@@ -25,6 +25,7 @@ logger = logging.getLogger(__name__)
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
test_data_file_path = "test_data.py"
|
|
28
|
+
data_provider_path = "data_provider.py"
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
@dataclass
|
|
@@ -118,6 +119,7 @@ class EnhancementProcessor:
|
|
|
118
119
|
base_files: Dict[str, str],
|
|
119
120
|
directory_files: List[Dict[str, Any]],
|
|
120
121
|
grouped_endpoints: Dict[str, List[Endpoint]],
|
|
122
|
+
db_type: str = "",
|
|
121
123
|
) -> Tuple[List[Dict[str, Any]], List[str]]:
|
|
122
124
|
"""Process workflow enhancements"""
|
|
123
125
|
enhanced_directory_files: List[Dict[str, Any]] = []
|
|
@@ -134,10 +136,13 @@ class EnhancementProcessor:
|
|
|
134
136
|
first_workflow = base_workflow_files[0]
|
|
135
137
|
# Get the content from the dictionary - adjust key name as needed
|
|
136
138
|
base_workflow_content = first_workflow.get("base_workflow.py", "")
|
|
137
|
-
|
|
138
139
|
for workflow_item in directory_files:
|
|
139
140
|
enhanced_workflow_item = await self._enhance_single_workflow(
|
|
140
|
-
workflow_item,
|
|
141
|
+
workflow_item,
|
|
142
|
+
base_files,
|
|
143
|
+
base_workflow_content,
|
|
144
|
+
grouped_endpoints,
|
|
145
|
+
db_type,
|
|
141
146
|
)
|
|
142
147
|
if enhanced_workflow_item:
|
|
143
148
|
enhanced_directory_files.append(enhanced_workflow_item["files"])
|
|
@@ -151,6 +156,7 @@ class EnhancementProcessor:
|
|
|
151
156
|
base_files: Dict[str, str],
|
|
152
157
|
base_workflow_files: str,
|
|
153
158
|
grouped_endpoints: Dict[str, List[Endpoint]],
|
|
159
|
+
db_type: str = "",
|
|
154
160
|
) -> Dict[str, Any] | None:
|
|
155
161
|
"""Enhance a single workflow file"""
|
|
156
162
|
for key, value in workflow_item.items():
|
|
@@ -164,6 +170,7 @@ class EnhancementProcessor:
|
|
|
164
170
|
base_workflow=base_workflow_files,
|
|
165
171
|
grouped_enpoints=workflow_endpoints_dict,
|
|
166
172
|
auth_endpoints=auth_endpoints,
|
|
173
|
+
db_type=db_type,
|
|
167
174
|
)
|
|
168
175
|
if enhanced_workflow:
|
|
169
176
|
return {
|
|
@@ -174,14 +181,19 @@ class EnhancementProcessor:
|
|
|
174
181
|
return None
|
|
175
182
|
|
|
176
183
|
async def process_test_data_enhancement(
|
|
177
|
-
self, base_files: Dict[str, str], endpoints: List[Endpoint]
|
|
184
|
+
self, base_files: Dict[str, str], endpoints: List[Endpoint], db_type: str = ""
|
|
178
185
|
) -> Tuple[Dict[str, str], List[str]]:
|
|
179
186
|
"""Process test data enhancement"""
|
|
180
187
|
enhanced_files = {}
|
|
181
188
|
enhancements = []
|
|
182
189
|
if self.ai_config and self.ai_config.enhance_test_data:
|
|
183
190
|
enhanced_test_data = await self.locust_generator.enhance_test_data_file(
|
|
184
|
-
base_files.get(test_data_file_path, ""),
|
|
191
|
+
base_files.get(test_data_file_path, ""),
|
|
192
|
+
endpoints,
|
|
193
|
+
db_type,
|
|
194
|
+
base_files.get(data_provider_path, ""),
|
|
195
|
+
base_files.get("db_config.py", ""),
|
|
196
|
+
data_provider_path,
|
|
185
197
|
)
|
|
186
198
|
if enhanced_test_data:
|
|
187
199
|
enhanced_files[test_data_file_path] = enhanced_test_data
|
|
@@ -289,6 +301,7 @@ class HybridLocustGenerator:
|
|
|
289
301
|
custom_requirement: Optional[str] = None,
|
|
290
302
|
target_host: Optional[str] = None,
|
|
291
303
|
include_auth: bool = True,
|
|
304
|
+
db_type: str = "",
|
|
292
305
|
) -> Tuple[Dict[str, str], List[Dict[str, Any]]]:
|
|
293
306
|
"""
|
|
294
307
|
Generate Locust tests using hybrid approach
|
|
@@ -308,6 +321,7 @@ class HybridLocustGenerator:
|
|
|
308
321
|
api_info,
|
|
309
322
|
include_auth=include_auth,
|
|
310
323
|
target_host=target_host,
|
|
324
|
+
db_type=db_type,
|
|
311
325
|
)
|
|
312
326
|
)
|
|
313
327
|
|
|
@@ -322,6 +336,7 @@ class HybridLocustGenerator:
|
|
|
322
336
|
directory_files,
|
|
323
337
|
grouped_enpoints,
|
|
324
338
|
custom_requirement,
|
|
339
|
+
db_type,
|
|
325
340
|
)
|
|
326
341
|
if enhancement_result.success:
|
|
327
342
|
logger.info(
|
|
@@ -422,6 +437,7 @@ class HybridLocustGenerator:
|
|
|
422
437
|
directory_files: List[Dict[str, Any]],
|
|
423
438
|
grouped_endpoints: Dict[str, List[Endpoint]],
|
|
424
439
|
custom_requirement: Optional[str] = None,
|
|
440
|
+
db_type: str = "",
|
|
425
441
|
) -> EnhancementResult:
|
|
426
442
|
"""Enhance base files with AI - Refactored for reduced cognitive complexity"""
|
|
427
443
|
start_time = asyncio.get_event_loop().time()
|
|
@@ -434,6 +450,7 @@ class HybridLocustGenerator:
|
|
|
434
450
|
directory_files,
|
|
435
451
|
grouped_endpoints,
|
|
436
452
|
custom_requirement,
|
|
453
|
+
db_type,
|
|
437
454
|
)
|
|
438
455
|
|
|
439
456
|
processing_time = asyncio.get_event_loop().time() - start_time
|
|
@@ -462,6 +479,7 @@ class HybridLocustGenerator:
|
|
|
462
479
|
directory_files: List[Dict[str, Any]],
|
|
463
480
|
grouped_endpoints: Dict[str, List[Endpoint]],
|
|
464
481
|
custom_requirement: Optional[str] = None,
|
|
482
|
+
db_type: str = "",
|
|
465
483
|
) -> EnhancementResult:
|
|
466
484
|
"""Process all enhancements using the enhancement processor"""
|
|
467
485
|
processor = EnhancementProcessor(self.ai_config, self)
|
|
@@ -476,7 +494,7 @@ class HybridLocustGenerator:
|
|
|
476
494
|
processor.process_domain_flows_enhancement(
|
|
477
495
|
endpoints, api_info, custom_requirement
|
|
478
496
|
),
|
|
479
|
-
processor.process_test_data_enhancement(base_files, endpoints),
|
|
497
|
+
processor.process_test_data_enhancement(base_files, endpoints, db_type),
|
|
480
498
|
processor.process_validation_enhancement(base_files, endpoints),
|
|
481
499
|
]
|
|
482
500
|
|
|
@@ -501,7 +519,7 @@ class HybridLocustGenerator:
|
|
|
501
519
|
workflow_files,
|
|
502
520
|
workflow_enhancements,
|
|
503
521
|
) = await processor.process_workflow_enhancements(
|
|
504
|
-
base_files, directory_files, grouped_endpoints
|
|
522
|
+
base_files, directory_files, grouped_endpoints, db_type
|
|
505
523
|
)
|
|
506
524
|
enhanced_directory_files.extend(workflow_files)
|
|
507
525
|
enhancements_applied.extend(workflow_enhancements)
|
|
@@ -557,6 +575,7 @@ class HybridLocustGenerator:
|
|
|
557
575
|
base_workflow: str,
|
|
558
576
|
grouped_enpoints: Dict[str, List[Endpoint]],
|
|
559
577
|
auth_endpoints: List[Endpoint],
|
|
578
|
+
db_type: str = "",
|
|
560
579
|
) -> Optional[str]:
|
|
561
580
|
try:
|
|
562
581
|
template = self.jinja_env.get_template("workflow.j2")
|
|
@@ -568,6 +587,7 @@ class HybridLocustGenerator:
|
|
|
568
587
|
base_workflow=base_workflow,
|
|
569
588
|
auth_endpoints=auth_endpoints,
|
|
570
589
|
base_content=base_content,
|
|
590
|
+
db_type=db_type,
|
|
571
591
|
)
|
|
572
592
|
enhanced_content = await self._call_ai_service(prompt)
|
|
573
593
|
return enhanced_content
|
|
@@ -577,7 +597,13 @@ class HybridLocustGenerator:
|
|
|
577
597
|
return ""
|
|
578
598
|
|
|
579
599
|
async def enhance_test_data_file(
|
|
580
|
-
self,
|
|
600
|
+
self,
|
|
601
|
+
base_content: str,
|
|
602
|
+
endpoints: List[Endpoint],
|
|
603
|
+
db_type: str = "",
|
|
604
|
+
data_provider: str = "",
|
|
605
|
+
db_config: str = "",
|
|
606
|
+
data_provider_path: str = "",
|
|
581
607
|
) -> Optional[str]:
|
|
582
608
|
"""Enhance test data generation with domain knowledge"""
|
|
583
609
|
|
|
@@ -592,11 +618,14 @@ class HybridLocustGenerator:
|
|
|
592
618
|
"base_content": base_content,
|
|
593
619
|
"schemas_info": schemas_info,
|
|
594
620
|
"endpoints": endpoints,
|
|
621
|
+
"db_type": db_type,
|
|
622
|
+
"data_provider_content": data_provider,
|
|
623
|
+
"db_config": db_config,
|
|
624
|
+
"data_provider_path": data_provider_path,
|
|
595
625
|
}
|
|
596
626
|
|
|
597
627
|
# Render enhanced content
|
|
598
628
|
prompt = template.render(**context)
|
|
599
|
-
|
|
600
629
|
enhanced_content = await self._call_ai_service(prompt)
|
|
601
630
|
if enhanced_content and self._validate_python_code(enhanced_content):
|
|
602
631
|
return enhanced_content
|
{devdox_ai_locust-0.1.3.post1 → devdox_ai_locust-0.1.4}/src/devdox_ai_locust/locust_generator.py
RENAMED
|
@@ -12,7 +12,8 @@ import black
|
|
|
12
12
|
from jinja2 import Environment, FileSystemLoader
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
import logging
|
|
15
|
-
from
|
|
15
|
+
from enum import Enum
|
|
16
|
+
from dataclasses import dataclass, asdict
|
|
16
17
|
from datetime import datetime
|
|
17
18
|
|
|
18
19
|
|
|
@@ -21,6 +22,48 @@ from devdox_ai_locust.utils.open_ai_parser import Endpoint, Parameter
|
|
|
21
22
|
logger = logging.getLogger(__name__)
|
|
22
23
|
|
|
23
24
|
|
|
25
|
+
class DatabaseType(Enum):
|
|
26
|
+
"""Supported database types for testing"""
|
|
27
|
+
|
|
28
|
+
MONGO = "mongo"
|
|
29
|
+
POSTGRES = "postgres"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class MongoDBConfig:
|
|
34
|
+
"""MongoDB-specific configuration"""
|
|
35
|
+
|
|
36
|
+
use_realistic_data: str = "true"
|
|
37
|
+
enable_mongodb: str = "false"
|
|
38
|
+
use_mongodb_for_test_data: str = "false"
|
|
39
|
+
mongodb_uri: str = "mongodb://localhost:27017/"
|
|
40
|
+
mongodb_database: str = "locust_test_data"
|
|
41
|
+
MONGODB_MAX_POOL_SIZE: int = 100
|
|
42
|
+
MONGODB_MIN_POOL_SIZE: int = 10
|
|
43
|
+
|
|
44
|
+
# MongoDB Timeout Settings
|
|
45
|
+
MONGODB_CONNECT_TIMEOUT_MS: int = 5000
|
|
46
|
+
MONGODB_SERVER_SELECTION_TIMEOUT_MS: int = 5000
|
|
47
|
+
MONGODB_SOCKET_TIMEOUT_MS: int = 10000
|
|
48
|
+
MONGODB_MAX_IDLE_TIME_MS: int = 60000
|
|
49
|
+
MONGODB_WAIT_QUEUE_TIMEOUT_MS: int = 10000
|
|
50
|
+
|
|
51
|
+
# MongoDB Collection Names to be added
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class PostgreSQLConfig:
|
|
56
|
+
"""PostgreSQL-specific configuration"""
|
|
57
|
+
|
|
58
|
+
host: str = "localhost"
|
|
59
|
+
port: str = "5432"
|
|
60
|
+
database: str = "test_db"
|
|
61
|
+
user: str = "test_user"
|
|
62
|
+
password: str = "test_password"
|
|
63
|
+
pool_size: str = "10"
|
|
64
|
+
max_overflow: str = "20"
|
|
65
|
+
|
|
66
|
+
|
|
24
67
|
@dataclass
|
|
25
68
|
class TestDataConfig:
|
|
26
69
|
"""Configuration for test data generation"""
|
|
@@ -100,6 +143,7 @@ class LocustTestGenerator:
|
|
|
100
143
|
api_info: Dict[str, Any],
|
|
101
144
|
include_auth: bool = True,
|
|
102
145
|
target_host: Optional[str] = None,
|
|
146
|
+
db_type: str = "",
|
|
103
147
|
) -> Tuple[Dict[str, str], List[Dict[str, Any]], Dict[str, List[Endpoint]]]:
|
|
104
148
|
"""
|
|
105
149
|
Generate complete Locust test suite from parsed endpoints
|
|
@@ -121,14 +165,23 @@ class LocustTestGenerator:
|
|
|
121
165
|
"locustfile.py": self._generate_main_locustfile(
|
|
122
166
|
endpoints, api_info, list(grouped_enpoint.keys())
|
|
123
167
|
),
|
|
124
|
-
"test_data.py": self._generate_test_data_file(),
|
|
168
|
+
"test_data.py": self._generate_test_data_file(db_type),
|
|
125
169
|
"config.py": self._generate_config_file(api_info),
|
|
126
170
|
"utils.py": self._generate_utils_file(),
|
|
127
171
|
"custom_flows.py": self._generate_custom_flows_file(),
|
|
128
172
|
"requirements.txt": self._generate_requirements_file(),
|
|
129
|
-
"README.md": self._generate_readme_file(api_info),
|
|
130
|
-
".env.example": self._generate_env_example(
|
|
173
|
+
"README.md": self._generate_readme_file(api_info, db_type),
|
|
174
|
+
".env.example": self._generate_env_example(
|
|
175
|
+
api_info, target_host, db_type
|
|
176
|
+
),
|
|
131
177
|
}
|
|
178
|
+
if db_type != "":
|
|
179
|
+
self.generated_files["db_config.py"] = self._generate_db_file(
|
|
180
|
+
db_type, "db_config.py.j2"
|
|
181
|
+
)
|
|
182
|
+
self.generated_files["data_provider.py"] = self._generate_db_file(
|
|
183
|
+
db_type, "data_provider.py.j2"
|
|
184
|
+
)
|
|
132
185
|
|
|
133
186
|
return self.generated_files, workflows_files, grouped_enpoint
|
|
134
187
|
except Exception as e:
|
|
@@ -639,10 +692,13 @@ class LocustTestGenerator:
|
|
|
639
692
|
|
|
640
693
|
'''
|
|
641
694
|
|
|
642
|
-
def _generate_test_data_file(self) -> str:
|
|
695
|
+
def _generate_test_data_file(self, db_type: str = "") -> str:
|
|
643
696
|
"""Generate test_data.py file content"""
|
|
697
|
+
data_provider_content = None
|
|
698
|
+
if db_type == DatabaseType.MONGO.value:
|
|
699
|
+
data_provider_content = "mongo_data_provider"
|
|
644
700
|
template = self.jinja_env.get_template("test_data.py.j2")
|
|
645
|
-
return template.render()
|
|
701
|
+
return template.render(data_provider_content=data_provider_content)
|
|
646
702
|
|
|
647
703
|
def _generate_config_file(self, api_info: Dict[str, Any]) -> str:
|
|
648
704
|
"""Generate config.py file content"""
|
|
@@ -665,8 +721,16 @@ class LocustTestGenerator:
|
|
|
665
721
|
content = template.render()
|
|
666
722
|
return content
|
|
667
723
|
|
|
724
|
+
def _generate_db_file(self, db_type: str, file_name: str) -> str:
|
|
725
|
+
"""Generate db file content"""
|
|
726
|
+
template = self.jinja_env.get_template(db_type + "/" + file_name)
|
|
727
|
+
return template.render()
|
|
728
|
+
|
|
668
729
|
def _generate_env_example(
|
|
669
|
-
self,
|
|
730
|
+
self,
|
|
731
|
+
api_info: Dict[str, Any],
|
|
732
|
+
target_host: Optional[str] = None,
|
|
733
|
+
db_type: str = "",
|
|
670
734
|
) -> str:
|
|
671
735
|
"""Generate .env.example file content"""
|
|
672
736
|
try:
|
|
@@ -686,12 +750,15 @@ class LocustTestGenerator:
|
|
|
686
750
|
"LOCUST_SPAWN_RATE": "5",
|
|
687
751
|
"LOCUST_RUN_TIME": "10m",
|
|
688
752
|
"LOCUST_HOST": locust_host,
|
|
689
|
-
"USE_REALISTIC_DATA": "true",
|
|
690
753
|
"DATA_SEED": "42",
|
|
691
754
|
"REQUEST_TIMEOUT": "30",
|
|
692
755
|
"MAX_RETRIES": "3",
|
|
693
756
|
}
|
|
694
757
|
|
|
758
|
+
if db_type == DatabaseType.MONGO.value:
|
|
759
|
+
mongodb_config = MongoDBConfig()
|
|
760
|
+
environment_vars.update(asdict(mongodb_config))
|
|
761
|
+
|
|
695
762
|
context = {
|
|
696
763
|
"environment_vars": environment_vars,
|
|
697
764
|
"api_info": api_info,
|
|
@@ -706,15 +773,23 @@ class LocustTestGenerator:
|
|
|
706
773
|
logger.error(f"❌ Failed to generate .env.example from template: {e}")
|
|
707
774
|
return ""
|
|
708
775
|
|
|
709
|
-
def _generate_readme_file(self, api_info: Dict[str, Any]) -> str:
|
|
776
|
+
def _generate_readme_file(self, api_info: Dict[str, Any], db_type: str = "") -> str:
|
|
710
777
|
try:
|
|
711
778
|
# Get the template
|
|
712
779
|
template = self.jinja_env.get_template("readme.md.j2")
|
|
780
|
+
db_using = ""
|
|
781
|
+
if db_type == DatabaseType.MONGO.value:
|
|
782
|
+
template_db = self.jinja_env.get_template(
|
|
783
|
+
DatabaseType.MONGO.value + "/db_integration.j2"
|
|
784
|
+
)
|
|
785
|
+
|
|
786
|
+
db_using = template_db.render()
|
|
713
787
|
|
|
714
788
|
# Prepare template context
|
|
715
789
|
context = {
|
|
716
790
|
"api_info": api_info,
|
|
717
791
|
"generated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
|
792
|
+
"db_using": db_using,
|
|
718
793
|
}
|
|
719
794
|
|
|
720
795
|
# Render the template
|