11import asyncio
2+ from pathlib import Path
23import sys
34from typing import Literal
45from fastmcp import Context
78import subprocess as sp
89from models import AAZRequest
910
11+ paths = {
12+ "aaz" : os .getenv ("AAZ_PATH" , "/workspaces-src/aaz" ),
13+ "cli" : "/workspaces/azure-cli" ,
14+ "cli_extension" : os .getenv ("CLI_EXTENSION_PATH" , "/workspaces-src/azure-cli-extensions" ),
15+ "swagger_path" : os .getenv ("SWAGGER_PATH" , "/workspaces-src/azure-rest-api-specs" )
16+ }
17+
1018async def fetch_available_services ():
1119 """Fetch available services from azure-rest-api-specs repository."""
1220 url = "https://api.github.com/repos/a0x1ab/azure-rest-api-specs/contents/specification"
@@ -22,12 +30,6 @@ async def fetch_available_services():
2230
2331async def validate_paths (ctx : Context ) -> dict :
2432 """Validate and get correct paths for required directories."""
25- paths = {
26- "aaz" : os .getenv ("AAZ_PATH" , "/workspaces-src/aaz" ),
27- "cli" : "/workspaces/azure-cli" ,
28- "cli_extension" : os .getenv ("CLI_EXTENSION_PATH" , "/workspaces-src/azure-cli-extensions" ),
29- "swagger_path" : os .getenv ("SWAGGER_PATH" , "/workspaces-src/azure-rest-api-specs" )
30- }
3133
3234 await ctx .info ("az_cli : Validating local paths..." )
3335 await ctx .report_progress (progress = 5 , total = 100 )
@@ -182,7 +184,6 @@ async def browse_specs(ctx: Context, base_path: str):
182184 return result
183185
184186async def run_command (ctx : Context , command : str , step_name : str , progress_start : int , progress_end : int ):
185- """Run a shell command and report progress."""
186187 await ctx .info (f"az_cli : Starting: { step_name } " )
187188 process = await asyncio .create_subprocess_shell (
188189 command ,
@@ -197,20 +198,23 @@ async def run_command(ctx: Context, command: str, step_name: str, progress_start
197198 while True :
198199 line = await process .stdout .readline ()
199200 if not line :
200- break
201+ if process .returncode is not None :
202+ break
203+ await asyncio .sleep (0.1 )
204+ continue
201205 lines_count += 1
202206 await ctx .info (f"az_cli : { line .decode ().rstrip ()} " )
203207 progress = progress_start + min (progress_range , int ((lines_count / total_lines_estimate ) * progress_range ))
204208 await ctx .report_progress (progress , 100 )
205209
206210 await process .wait ()
211+
207212 if process .returncode != 0 :
208213 raise RuntimeError (f"{ step_name } failed: { command } " )
209214
210215 await ctx .report_progress (progress_end , 100 )
211216 await ctx .info (f"az_cli : Completed: { step_name } " )
212217
213-
214218async def execute_commands (ctx : Context , paths : dict , request : AAZRequest ):
215219 cmd1 = (
216220 f"aaz-dev command-model generate-from-swagger "
@@ -241,3 +245,41 @@ async def execute_commands(ctx: Context, paths: dict, request: AAZRequest):
241245 return f"Code generation failed: { str (e )} "
242246
243247 return "Azure CLI code generation completed successfully!"
248+
249+ async def generate_tests (ctx : "Context" ):
250+ await ctx .info ("Starting test generation workflow." )
251+
252+ module_name = getattr (ctx , "generated_module" , None )
253+ if not module_name :
254+ response = await ctx .elicit ("Enter the module/extension name to generate tests for:" )
255+ if not response .action == "accept" or not response .data :
256+ return "Test generation cancelled."
257+ module_name = response .data
258+ else :
259+ await ctx .info (f"Detected generated module: { module_name } " )
260+
261+ aaz_path = Path (f"{ paths ['cli' ]} /src/azure-cli/azure/cli/command_modules/{ module_name } /aaz" )
262+ if not aaz_path .exists ():
263+ return f"AAZ path not found for module '{ module_name } '"
264+
265+ commands = []
266+ for file in aaz_path .rglob ("*.py" ):
267+ with open (file , "r" , encoding = "utf-8" ) as f :
268+ for line in f :
269+ if line .strip ().startswith ("def " ):
270+ commands .append (line .strip ().replace ("def " , "" ).split ("(" )[0 ])
271+
272+ test_dir = Path (f"{ paths ['cli' ]} /src/azure-cli/azure/cli/command_modules/{ module_name } /tests/latest" )
273+ test_dir .mkdir (parents = True , exist_ok = True )
274+ test_file = test_dir / f"test_{ module_name } .py"
275+
276+ with open (test_file , "w" , encoding = "utf-8" ) as f :
277+ f .write ("import unittest\n " )
278+ f .write ("from azure.cli.testsdk import ScenarioTest\n \n " )
279+ f .write (f"class { module_name .capitalize ()} ScenarioTest(ScenarioTest):\n \n " )
280+ for cmd in commands :
281+ f .write (f" def test_{ cmd } (self):\n " )
282+ f .write (f" self.cmd('az { module_name } { cmd } --resource-name test-resource')\n \n " )
283+
284+ await ctx .info (f"Generated test file: { test_file } " )
285+ return f"Test generation completed for module '{ module_name } '."
0 commit comments