-
Couldn't load subscription status.
- Fork 1k
feat(cloudwatch-appsignals-mcp-server): Add get_enablement_guide MCP tool #1585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e964e4d
48fac03
b4281cd
4e63eb4
6c5b3cb
bd393b1
73a3cfb
f0c36ea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Placeholder content just to verify the tool can fetch the file. |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,142 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # you may not use this file except in compliance with the License. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # You may obtain a copy of the License at | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Unless required by applicable law or agreed to in writing, software | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # See the License for the specific language governing permissions and | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # limitations under the License. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| """CloudWatch Application Signals MCP Server - Enablement Tools.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| from loguru import logger | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| from pathlib import Path | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| async def get_enablement_guide( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we add tool annotations? Not sure if that's common practice in this MCP/repo |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| platform: str, language: str, iac_directory: str, app_directory: str | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whats the value of iac_directory and app_directory? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible for platform and language be an enum? Just something to clearly indicate only specific values are acceptable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should naming be more clear? e.g There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How long do we expect guides to be? Should we consider having the tool return chunks of the guide, based on character limits: https://github.com/anthropics/skills/blob/main/mcp-builder/reference/mcp_best_practices.md#5-character-limits-and-truncation |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> str: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Get enablement guide for AWS Application Signals. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| This tool returns step-by-step enablement instructions that guide you through | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| modifying your infrastructure and application code to enable Application Signals. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| After calling this tool, you should: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1. Read the existing IaC files from iac_directory | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2. Read the existing application files from app_directory | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3. Apply the changes specified in the enablement guide to those files | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 4. Verify the changes are correct and complete | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+30
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel this is almost guaranteed to exhaust the context window for a sufficiently large application. Should we recommend creating a work list based on the response and work through the worklist systematically? Ideally each instruction tells the agent what code to look for, etc. rather than trying to have it load the entire IaC and application into it's context.
Comment on lines
+30
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
What kind of verification do we expect the agent to do? Presumably there should be something in the guide itself? |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| platform: The deployment platform (ec2, ecs, lambda, eks) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Should we also give instructions for HOW to determine this, given arbitrary IaC? Similar comment goes for language. |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| language: The programming language (python, nodejs, java, dotnet) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+36
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We might want to consider a fallback: If agent finds a service not meeting these specs, maybe it should look at https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Application-Monitoring-Sections.html/ subpages Example: We do support ruby, and talk about it in docs, right? |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| iac_directory: ABSOLUTE path to the IaC directory (e.g., /home/user/project/infrastructure) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| app_directory: ABSOLUTE path to the application code directory (e.g., /home/user/project/app) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| Returns: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enablement guide with step-by-step instructions | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe indicate the format we are returning in? Should we support both md and json? |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+24
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's hard to validate if this is a sufficient summary, did we do some testing showing that this tool gets invoked correctly based on some prompts? I know we are working on automation, but even some manual testing would help. Seemingly we should have some instructions like "use this tool when..." |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'get_enablement_guide called: platform={platform}, language={language}, ' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'iac_directory={iac_directory}, app_directory={app_directory}' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| platform = platform.lower().strip() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| language = language.lower().strip() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| valid_platforms = ['ec2', 'ecs', 'lambda', 'eks'] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if platform not in valid_platforms: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return f"Error: Invalid platform: '{platform}'. Valid platforms are: {', '.join(valid_platforms)}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| valid_languages = ['python', 'nodejs', 'java', 'dotnet'] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if language not in valid_languages: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return f"Error: Invalid language '{language}'. Valid languages are: {', '.join(valid_languages)}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Validate that paths are absolute | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| iac_path = Path(iac_directory) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| app_path = Path(app_directory) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not iac_path.is_absolute(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| error_msg = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'Error: iac_directory must be an absolute path.\n\n' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'Received: {iac_directory}\n' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'Please provide an absolute path (e.g., /home/user/project/infrastructure)' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error(error_msg) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return error_msg | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not app_path.is_absolute(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| error_msg = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'Error: app_directory must be an absolute path.\n\n' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'Received: {app_directory}\n' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'Please provide an absolute path (e.g., /home/user/project/app)' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error(error_msg) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return error_msg | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+64
to
+80
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally unclear why this is so important. Also is |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(f'IaC path: {iac_path}') | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(f'App path: {app_path}') | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+82
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably not helpful, we already have |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not iac_path.exists(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| error_msg = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'Error: IaC directory does not exist: {iac_path}\n\n' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'Please provide a valid path to your infrastructure code directory.' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error(error_msg) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return error_msg | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not app_path.exists(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| error_msg = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'Error: Application directory does not exist: {app_path}\n\n' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'Please provide a valid path to your application code directory.' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error(error_msg) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return error_msg | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+85
to
+99
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| guides_dir = Path(__file__).parent / 'enablement_guides' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| template_file = guides_dir / 'templates' / platform / f'{platform}-{language}-enablement.md' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(f'Looking for enablement guide: {template_file}') | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: would move to line 100 |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not template_file.exists(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.warning(f'Enablement guide not found: {template_file}') | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f"Error: Enablement guide for platform '{platform}' and language '{language}' " | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f' is not yet available.\n\n' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'Currently supported combinations:\n' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'- EC2 + Python\n\n' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| f'Requested: {platform} + {language}' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+109
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So what should agent do? Lets not hardcode EC2/Python.
Suggested change
Comment on lines
+107
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use a similar format for errors consistently:
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| with open(template_file, 'r') as f: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| guide_content = f.read() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| context = f"""# Application Signals Enablement Guide | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Context | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Platform:** {platform} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Language:** {language} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| **IaC Directory (absolute path):** `{iac_path}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Application Directory (absolute path):** `{app_path}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Instructions | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1. Use the ABSOLUTE PATHS above when reading and writing files | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2. **IMPORTANT:** Only modify the IaC code or Dockerfiles. Actual application code should not be modified. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Read application files if needed to understand the setup, but do not modify them. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+132
to
+133
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm - is this always true? We may need agent to ask user about this at least. |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3. Follow the step-by-step enablement guide below to enable Application Signals | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like some/all of this should be in the tool description, not sure if we need to double-embed this information? |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info(f'Successfully loaded enablement guide: {template_file.name}') | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return context + guide_content | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| except Exception as e: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error(f'Error reading enablement guide {template_file}: {e}') | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return f'Error: Failed to read enablement guide. {str(e)}' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+141
to
+142
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See https://github.com/awslabs/mcp/pull/1585/files#r2471352926 Also the error is not really helpful to agent, what should it do now? |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| """Tests for enablement_tools module.""" | ||
|
|
||
| import pytest | ||
| import tempfile | ||
| from awslabs.cloudwatch_appsignals_mcp_server.enablement_tools import get_enablement_guide | ||
| from pathlib import Path | ||
|
|
||
|
|
||
| class TestGetEnablementGuide: | ||
| """Test get_enablement_guide function.""" | ||
|
|
||
| @pytest.fixture | ||
| def temp_directories(self): | ||
| """Create temporary IaC and app directories for testing.""" | ||
| with tempfile.TemporaryDirectory() as tmpdir: | ||
| base = Path(tmpdir) | ||
| iac_dir = base / 'infrastructure' / 'cdk' | ||
| app_dir = base / 'app' / 'src' | ||
|
|
||
| iac_dir.mkdir(parents=True) | ||
| app_dir.mkdir(parents=True) | ||
|
|
||
| yield {'iac': str(iac_dir), 'app': str(app_dir)} | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_invalid_platform(self, temp_directories): | ||
| """Test with invalid platform.""" | ||
| result = await get_enablement_guide( | ||
| platform='invalid', | ||
| language='python', | ||
| iac_directory=temp_directories['iac'], | ||
| app_directory=temp_directories['app'], | ||
| ) | ||
|
|
||
| assert 'Error: Invalid platform' in result | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_invalid_language(self, temp_directories): | ||
| """Test with invalid language.""" | ||
| result = await get_enablement_guide( | ||
| platform='ec2', | ||
| language='invalid', | ||
| iac_directory=temp_directories['iac'], | ||
| app_directory=temp_directories['app'], | ||
| ) | ||
|
|
||
| assert 'Error: Invalid language' in result | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_nonexistent_iac_directory(self, temp_directories): | ||
| """Test with non-existent IaC directory.""" | ||
| result = await get_enablement_guide( | ||
| platform='ec2', | ||
| language='python', | ||
| iac_directory='/nonexistent/path', | ||
| app_directory=temp_directories['app'], | ||
| ) | ||
|
|
||
| assert 'Error: IaC directory does not exist' in result | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_nonexistent_app_directory(self, temp_directories): | ||
| """Test with non-existent app directory.""" | ||
| result = await get_enablement_guide( | ||
| platform='ec2', | ||
| language='python', | ||
| iac_directory=temp_directories['iac'], | ||
| app_directory='/nonexistent/path', | ||
| ) | ||
|
|
||
| assert 'Error: Application directory does not exist' in result | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_successful_guide_fetch(self, temp_directories, tmp_path, monkeypatch): | ||
| """Test successful guide fetching when template exists.""" | ||
| result = await get_enablement_guide( | ||
| platform='ec2', | ||
| language='python', | ||
| iac_directory=temp_directories['iac'], | ||
| app_directory=temp_directories['app'], | ||
| ) | ||
|
|
||
| assert '# Application Signals Enablement Guide' in result | ||
| assert 'Placeholder content just to verify the tool can fetch the file.' in result | ||
| assert temp_directories['iac'] in result | ||
| assert temp_directories['app'] in result | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_case_normalization(self, temp_directories): | ||
| """Test that platform and language are normalized to lowercase.""" | ||
| result = await get_enablement_guide( | ||
| platform='EC2', | ||
| language='PYTHON', | ||
| iac_directory=temp_directories['iac'], | ||
| app_directory=temp_directories['app'], | ||
| ) | ||
|
|
||
| assert '# Application Signals Enablement Guide' in result | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_whitespace_trimming(self, temp_directories): | ||
| """Test that whitespace is trimmed from inputs.""" | ||
| result = await get_enablement_guide( | ||
| platform=' ec2 ', | ||
| language=' python ', | ||
| iac_directory=temp_directories['iac'], | ||
| app_directory=temp_directories['app'], | ||
| ) | ||
|
|
||
| assert '# Application Signals Enablement Guide' in result | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_all_valid_platforms(self, temp_directories): | ||
| """Test that all valid platforms are accepted.""" | ||
| valid_platforms = ['ec2', 'ecs', 'lambda', 'eks'] | ||
|
|
||
| for platform in valid_platforms: | ||
| result = await get_enablement_guide( | ||
| platform=platform, | ||
| language='python', | ||
| iac_directory=temp_directories['iac'], | ||
| app_directory=temp_directories['app'], | ||
| ) | ||
|
|
||
| assert 'Error: Invalid platform' not in result | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_all_valid_languages(self, temp_directories): | ||
| """Test that all valid languages are accepted.""" | ||
| valid_languages = ['python', 'nodejs', 'java', 'dotnet'] | ||
|
|
||
| for language in valid_languages: | ||
| result = await get_enablement_guide( | ||
| platform='ec2', | ||
| language=language, | ||
| iac_directory=temp_directories['iac'], | ||
| app_directory=temp_directories['app'], | ||
| ) | ||
|
|
||
| assert 'Error: Invalid language' not in result | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_relative_path_rejected(self, temp_directories): | ||
| """Test that relative paths are rejected with clear error message.""" | ||
| result = await get_enablement_guide( | ||
| platform='ec2', | ||
| language='python', | ||
| iac_directory='infrastructure/cdk', | ||
| app_directory=temp_directories['app'], | ||
| ) | ||
|
|
||
| assert 'Error: iac_directory must be an absolute path' in result | ||
| assert 'infrastructure/cdk' in result | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_relative_app_directory_rejected(self, temp_directories): | ||
| """Test that relative app directory is rejected with clear error message.""" | ||
| result = await get_enablement_guide( | ||
| platform='ec2', | ||
| language='python', | ||
| iac_directory=temp_directories['iac'], | ||
| app_directory='app/src', | ||
| ) | ||
|
|
||
| assert 'Error: app_directory must be an absolute path' in result | ||
| assert 'app/src' in result | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_absolute_path_handling(self, temp_directories): | ||
| """Test that absolute paths are handled correctly.""" | ||
| result = await get_enablement_guide( | ||
| platform='ec2', | ||
| language='python', | ||
| iac_directory=temp_directories['iac'], | ||
| app_directory=temp_directories['app'], | ||
| ) | ||
|
|
||
| assert '# Application Signals Enablement Guide' in result | ||
| assert temp_directories['iac'] in result | ||
| assert temp_directories['app'] in result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be better?