Skip to main content
Glama
test_main.py19.7 kB
#!/usr/bin/env python3 """ Alpha ESS MCP Server - Comprehensive Test Suite Tests all MCP tool methods with real API calls. """ import asyncio import json import os from datetime import datetime, timedelta from dotenv import load_dotenv from main import ( authenticate_alphaess, get_alpha_ess_data, get_ess_list, get_last_power_data, get_one_day_power_data, get_one_date_energy_data, get_charge_config, get_discharge_config, set_battery_charge, set_battery_discharge ) load_dotenv() class AlphaESSTestSuite: """Comprehensive test suite for all Alpha ESS MCP Server methods""" def __init__(self): self.serial = None self.results = [] self.total_tests = 0 self.passed_tests = 0 def check_credentials(self): """Check if credentials are available""" app_id = os.getenv('ALPHA_ESS_APP_ID') app_secret = os.getenv('ALPHA_ESS_APP_SECRET') if not app_id or not app_secret: print("ERROR: Missing Alpha ESS credentials in .env file") return False return True def log_result(self, test_name, success, message=""): """Log test result""" self.total_tests += 1 if success: self.passed_tests += 1 print(f"PASS: {test_name}") else: print(f"FAIL: {test_name} - {message}") if message and success: print(f" {message}") async def test_authenticate(self): """Test authentication method""" try: result = await authenticate_alphaess() success = result['success'] message = "Authentication successful" if success else result['message'] self.log_result("authenticate_alphaess", success, message) return success except Exception as e: self.log_result("authenticate_alphaess", False, f"Exception: {str(e)}") return False async def test_get_alpha_ess_data(self): """Test get_alpha_ess_data method""" try: result = await get_alpha_ess_data() success = result['success'] message = "Statistical data retrieved" if success else result['message'] self.log_result("get_alpha_ess_data", success, message) return success except Exception as e: self.log_result("get_alpha_ess_data", False, f"Exception: {str(e)}") return False async def test_get_ess_list(self): """Test get_ess_list method and extract serial for other tests""" try: result = await get_ess_list() success = result['success'] if success: structured = result.get('structured', {}) systems = structured.get('systems', []) recommended_serial = structured.get('recommended_serial') # Store serial for other tests if recommended_serial: self.serial = recommended_serial elif systems: self.serial = systems[0].get('serial') message = f"Found {len(systems)} systems, using serial: {self.serial}" self.log_result("get_ess_list", success, message) else: self.log_result("get_ess_list", success, result['message']) return success except Exception as e: self.log_result("get_ess_list", False, f"Exception: {str(e)}") return False async def test_get_last_power_data(self): """Test get_last_power_data method""" try: result = await get_last_power_data(self.serial) success = result['success'] if success: structured = result.get('structured', {}) solar = structured.get('solar', {}).get('total_power', 0) battery = structured.get('battery', {}).get('state_of_charge', 0) message = f"Solar: {solar}W, Battery: {battery}%" else: message = result['message'] self.log_result("get_last_power_data", success, message) return success except Exception as e: self.log_result("get_last_power_data", False, f"Exception: {str(e)}") return False async def test_get_one_day_power_data(self): """Test get_one_day_power_data method""" try: yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d') result = await get_one_day_power_data(yesterday, self.serial) success = result['success'] if success: structured = result.get('structured', {}) series = structured.get('series', []) summary = structured.get('summary', {}) # Verify hourly data structure if series: first_record = series[0] expected_keys = {'timestamp', 'solar_power', 'load_power', 'battery_soc', 'grid_feedin', 'grid_import', 'ev_charging'} if not all(key in first_record for key in expected_keys): self.log_result("get_one_day_power_data", False, "Missing expected data fields") return False # Verify hourly timestamps for record in series: if not record['timestamp'].endswith(':00:00'): self.log_result("get_one_day_power_data", False, "Non-hourly timestamp found") return False # Check summary structure solar_kwh = summary.get('solar', {}).get('total_generation_kwh', 0) interval = summary.get('interval') if interval != "1 hour": self.log_result("get_one_day_power_data", False, "Incorrect interval in summary") return False message = (f"Retrieved {len(series)} hourly records, " f"{solar_kwh:.2f} kWh solar generation") else: message = result['message'] self.log_result("get_one_day_power_data", success, message) return success except Exception as e: self.log_result("get_one_day_power_data", False, f"Exception: {str(e)}") return False async def test_get_one_day_power_data_for_different_dates(self): """Test get_one_day_power_data for different dates to ensure data varies""" try: # Get data for one week ago date1_str = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d') result1 = await get_one_day_power_data(date1_str, self.serial) # Get data for two weeks ago date2_str = (datetime.now() - timedelta(days=14)).strftime('%Y-%m-%d') result2 = await get_one_day_power_data(date2_str, self.serial) # Check if both calls were successful if not (result1['success'] and result2['success']): self.log_result("get_one_day_power_data_for_different_dates", False, "API calls for different dates failed") return False # Extract the 'total_generation_kwh' value from the data kwh1 = result1.get('structured', {}).get('summary', {}).get('solar', {}).get( 'total_generation_kwh', 0) kwh2 = result2.get('structured', {}).get('summary', {}).get('solar', {}).get( 'total_generation_kwh', 0) # Assert that the values are not the same if kwh1 != kwh2: self.log_result("get_one_day_power_data_for_different_dates", True, f"kWh for {date1_str} ({kwh1}) differs from {date2_str} ({kwh2})") return True else: self.log_result("get_one_day_power_data_for_different_dates", False, f"kWh for {date1_str} ({kwh1}) is the same as {date2_str} ({kwh2})") return False except Exception as e: self.log_result("get_one_day_power_data_for_different_dates", False, f"Exception: {str(e)}") return False async def test_get_one_date_energy_data(self): """Test get_one_date_energy_data method""" try: yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d') result = await get_one_date_energy_data(yesterday, self.serial) success = result['success'] message = f"Energy data for {yesterday}" if success else result['message'] self.log_result("get_one_date_energy_data", success, message) return success except Exception as e: self.log_result("get_one_date_energy_data", False, f"Exception: {str(e)}") return False async def test_get_one_date_energy_data_for_different_dates(self): """Test get_one_date_energy_data for different dates to ensure data varies""" try: # Get data for one week ago date1_str = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d') result1 = await get_one_date_energy_data(date1_str, self.serial) # Get data for two weeks ago date2_str = (datetime.now() - timedelta(days=14)).strftime('%Y-%m-%d') result2 = await get_one_date_energy_data(date2_str, self.serial) # Check if both calls were successful if not (result1['success'] and result2['success']): self.log_result("get_one_date_energy_data_for_different_dates", False, "API calls for different dates failed") return False # Extract the 'epv' value from the data power1 = result1.get('data', {}).get('epv', 0) power2 = result2.get('data', {}).get('epv', 0) # Assert that the values are not the same if power1 != power2: self.log_result("get_one_date_energy_data_for_different_dates", True, f"Power for {date1_str} ({power1}) differs from {date2_str} ({power2})") return True else: self.log_result("get_one_date_energy_data_for_different_dates", False, f"Power for {date1_str} ({power1}) is the same as {date2_str} ({power2})") return False except Exception as e: self.log_result("get_one_date_energy_data_for_different_dates", False, f"Exception: {str(e)}") return False async def test_get_one_date_energy_data_for_different_dates(self): """Test get_one_date_energy_data for different dates to ensure data varies""" try: # Get data for yesterday yesterday_str = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d') yesterday_result = await get_one_date_energy_data(yesterday_str, self.serial) # Get data for the day before yesterday day_before_str = (datetime.now() - timedelta(days=2)).strftime('%Y-%m-%d') day_before_result = await get_one_date_energy_data(day_before_str, self.serial) # Check if both calls were successful if not (yesterday_result['success'] and day_before_result['success']): self.log_result("get_one_date_energy_data_for_different_dates", False, "API calls for different dates failed") return False # Extract the 'epv' value from the data yesterday_power = yesterday_result.get('data', {}).get('epv', 0) day_before_power = day_before_result.get('data', {}).get('epv', 0) # Assert that the values are not the same if yesterday_power != day_before_power: self.log_result("get_one_date_energy_data_for_different_dates", True, f"Yesterday's power ({yesterday_power}) differs from the day before's ({day_before_power})") return True else: self.log_result("get_one_date_energy_data_for_different_dates", False, f"Yesterday's power ({yesterday_power}) is the same as the day before's ({day_before_power})") return False except Exception as e: self.log_result("get_one_date_energy_data_for_different_dates", False, f"Exception: {str(e)}") return False async def test_get_charge_config(self): """Test get_charge_config method""" try: result = await get_charge_config(self.serial) success = result['success'] if success: structured = result.get('structured', {}) enabled = structured.get('enabled', False) limit = structured.get('charge_limit_soc', 0) message = f"Enabled: {enabled}, Limit: {limit}%" else: message = result['message'] self.log_result("get_charge_config", success, message) return success except Exception as e: self.log_result("get_charge_config", False, f"Exception: {str(e)}") return False async def test_get_discharge_config(self): """Test get_discharge_config method""" try: result = await get_discharge_config(self.serial) success = result['success'] if success: structured = result.get('structured', {}) enabled = structured.get('enabled', False) limit = structured.get('discharge_limit_soc', 0) message = f"Enabled: {enabled}, Limit: {limit}%" else: message = result['message'] self.log_result("get_discharge_config", success, message) return success except Exception as e: self.log_result("get_discharge_config", False, f"Exception: {str(e)}") return False async def test_set_battery_charge(self): """Test set_battery_charge method (non-disruptive)""" try: # Get current config first current_config = await get_charge_config(self.serial) if not current_config['success']: self.log_result("set_battery_charge", False, "Cannot get current config") return False # Extract current settings structured = current_config.get('structured', {}) enabled = structured.get('enabled', False) limit = structured.get('charge_limit_soc', 100) periods = structured.get('periods', []) period1 = periods[0] if len(periods) > 0 else {'start_time': '00:00', 'end_time': '00:00'} period2 = periods[1] if len(periods) > 1 else {'start_time': '00:00', 'end_time': '00:00'} # Set same configuration (no actual change) result = await set_battery_charge( enabled=enabled, dp1_start=period1['start_time'], dp1_end=period1['end_time'], dp2_start=period2['start_time'], dp2_end=period2['end_time'], charge_cutoff_soc=limit, serial=self.serial ) success = result['success'] message = f"Set charge config (no change)" if success else result['message'] self.log_result("set_battery_charge", success, message) return success except Exception as e: self.log_result("set_battery_charge", False, f"Exception: {str(e)}") return False async def test_set_battery_discharge(self): """Test set_battery_discharge method (non-disruptive)""" try: # Get current config first current_config = await get_discharge_config(self.serial) if not current_config['success']: self.log_result("set_battery_discharge", False, "Cannot get current config") return False # Extract current settings structured = current_config.get('structured', {}) enabled = structured.get('enabled', False) limit = structured.get('discharge_limit_soc', 10) periods = structured.get('periods', []) period1 = periods[0] if len(periods) > 0 else {'start_time': '00:00', 'end_time': '00:00'} period2 = periods[1] if len(periods) > 1 else {'start_time': '00:00', 'end_time': '00:00'} # Set same configuration (no actual change) result = await set_battery_discharge( enabled=enabled, dp1_start=period1['start_time'], dp1_end=period1['end_time'], dp2_start=period2['start_time'], dp2_end=period2['end_time'], discharge_cutoff_soc=limit, serial=self.serial ) success = result['success'] message = f"Set discharge config (no change)" if success else result['message'] self.log_result("set_battery_discharge", success, message) return success except Exception as e: self.log_result("set_battery_discharge", False, f"Exception: {str(e)}") return False async def run_all_tests(self): """Run all tests in sequence""" print("Alpha ESS MCP Server - Comprehensive Test Suite") print("=" * 50) if not self.check_credentials(): return False # Test authentication first if not await self.test_authenticate(): print("Authentication failed - stopping tests") return False # Get system list and serial if not await self.test_get_ess_list(): print("Cannot get system list - stopping tests") return False # Test all other methods await self.test_get_alpha_ess_data() await self.test_get_last_power_data() await self.test_get_one_day_power_data() await self.test_get_one_date_energy_data() await self.test_get_one_date_energy_data_for_different_dates() await self.test_get_charge_config() await self.test_get_discharge_config() await self.test_set_battery_charge() await self.test_set_battery_discharge() # Print summary print("=" * 50) print(f"Tests completed: {self.passed_tests}/{self.total_tests}") print(f"Success rate: {(self.passed_tests/self.total_tests)*100:.1f}%") if self.passed_tests == self.total_tests: print("ALL TESTS PASSED") return True else: print(f"{self.total_tests - self.passed_tests} tests failed") return False async def main(): """Run the comprehensive test suite""" test_suite = AlphaESSTestSuite() success = await test_suite.run_all_tests() return success if __name__ == "__main__": success = asyncio.run(main()) exit(0 if success else 1)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/michaelkrasa/alpha-ess-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server