You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							262 lines
						
					
					
						
							9.6 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							262 lines
						
					
					
						
							9.6 KiB
						
					
					
				
								#!/usr/bin/env python3
							 | 
						|
								"""
							 | 
						|
								DailyNotification Plugin Automated Test Suite
							 | 
						|
								Usage: python3 daily-notification-test.py [OPTIONS]
							 | 
						|
								"""
							 | 
						|
								
							 | 
						|
								import subprocess
							 | 
						|
								import time
							 | 
						|
								import json
							 | 
						|
								import sys
							 | 
						|
								import argparse
							 | 
						|
								from typing import Optional, Dict, Any, List
							 | 
						|
								from dataclasses import dataclass
							 | 
						|
								from enum import Enum
							 | 
						|
								
							 | 
						|
								class TestResult(Enum):
							 | 
						|
								    PASS = "PASS"
							 | 
						|
								    FAIL = "FAIL"
							 | 
						|
								    SKIP = "SKIP"
							 | 
						|
								
							 | 
						|
								@dataclass
							 | 
						|
								class TestCase:
							 | 
						|
								    name: str
							 | 
						|
								    description: str
							 | 
						|
								    result: TestResult
							 | 
						|
								    duration: float
							 | 
						|
								    error: Optional[str] = None
							 | 
						|
								
							 | 
						|
								class DailyNotificationTester:
							 | 
						|
								    def __init__(self, package: str = "com.timesafari.dailynotification", verbose: bool = False):
							 | 
						|
								        self.package = package
							 | 
						|
								        self.activity = f"{package}/.MainActivity"
							 | 
						|
								        self.verbose = verbose
							 | 
						|
								        self.test_results: List[TestCase] = []
							 | 
						|
								        
							 | 
						|
								    def log(self, message: str, level: str = "INFO"):
							 | 
						|
								        """Log message with timestamp"""
							 | 
						|
								        timestamp = time.strftime("%H:%M:%S")
							 | 
						|
								        if level == "ERROR":
							 | 
						|
								            print(f"❌ [{timestamp}] {message}")
							 | 
						|
								        elif level == "SUCCESS":
							 | 
						|
								            print(f"✅ [{timestamp}] {message}")
							 | 
						|
								        elif level == "WARNING":
							 | 
						|
								            print(f"⚠️  [{timestamp}] {message}")
							 | 
						|
								        elif level == "INFO":
							 | 
						|
								            print(f"ℹ️  [{timestamp}] {message}")
							 | 
						|
								        else:
							 | 
						|
								            print(f"[{timestamp}] {message}")
							 | 
						|
								    
							 | 
						|
								    def run_adb_command(self, command: str, capture_output: bool = True) -> subprocess.CompletedProcess:
							 | 
						|
								        """Run ADB command and return result"""
							 | 
						|
								        full_command = f"adb {command}"
							 | 
						|
								        if self.verbose:
							 | 
						|
								            self.log(f"Running: {full_command}")
							 | 
						|
								        
							 | 
						|
								        try:
							 | 
						|
								            return subprocess.run(
							 | 
						|
								                full_command, 
							 | 
						|
								                shell=True, 
							 | 
						|
								                capture_output=capture_output, 
							 | 
						|
								                text=True,
							 | 
						|
								                timeout=30
							 | 
						|
								            )
							 | 
						|
								        except subprocess.TimeoutExpired:
							 | 
						|
								            self.log(f"Command timed out: {full_command}", "ERROR")
							 | 
						|
								            raise
							 | 
						|
								    
							 | 
						|
								    def is_app_running(self) -> bool:
							 | 
						|
								        """Check if app is currently running"""
							 | 
						|
								        result = self.run_adb_command(f'shell "ps | grep {self.package}"')
							 | 
						|
								        return result.returncode == 0 and self.package in result.stdout
							 | 
						|
								    
							 | 
						|
								    def launch_app(self) -> bool:
							 | 
						|
								        """Launch the app"""
							 | 
						|
								        self.log("Launching app...")
							 | 
						|
								        result = self.run_adb_command(f"shell am start -n {self.activity}")
							 | 
						|
								        time.sleep(3)  # Wait for app to load
							 | 
						|
								        return self.is_app_running()
							 | 
						|
								    
							 | 
						|
								    def send_to_background(self) -> bool:
							 | 
						|
								        """Send app to background"""
							 | 
						|
								        self.log("Sending app to background...")
							 | 
						|
								        self.run_adb_command("shell input keyevent KEYCODE_HOME")
							 | 
						|
								        time.sleep(2)
							 | 
						|
								        return self.is_app_running()
							 | 
						|
								    
							 | 
						|
								    def force_stop_app(self) -> bool:
							 | 
						|
								        """Force stop the app"""
							 | 
						|
								        self.log("Force stopping app...")
							 | 
						|
								        self.run_adb_command(f"shell am force-stop {self.package}")
							 | 
						|
								        time.sleep(2)
							 | 
						|
								        return not self.is_app_running()
							 | 
						|
								    
							 | 
						|
								    def check_notification_logs(self, timeout: int = 60) -> bool:
							 | 
						|
								        """Check for notification success in logs"""
							 | 
						|
								        self.log(f"Checking notification logs (timeout: {timeout}s)...")
							 | 
						|
								        start_time = time.time()
							 | 
						|
								        
							 | 
						|
								        while time.time() - start_time < timeout:
							 | 
						|
								            result = self.run_adb_command("logcat -d")
							 | 
						|
								            if "Notification displayed successfully" in result.stdout:
							 | 
						|
								                return True
							 | 
						|
								            time.sleep(5)
							 | 
						|
								        return False
							 | 
						|
								    
							 | 
						|
								    def check_permissions(self) -> Dict[str, bool]:
							 | 
						|
								        """Check app permissions"""
							 | 
						|
								        self.log("Checking app permissions...")
							 | 
						|
								        result = self.run_adb_command(f"shell dumpsys package {self.package}")
							 | 
						|
								        
							 | 
						|
								        permissions = {
							 | 
						|
								            "notifications": "POST_NOTIFICATIONS" in result.stdout,
							 | 
						|
								            "exact_alarm": "SCHEDULE_EXACT_ALARM" in result.stdout,
							 | 
						|
								            "wake_lock": "WAKE_LOCK" in result.stdout
							 | 
						|
								        }
							 | 
						|
								        
							 | 
						|
								        return permissions
							 | 
						|
								    
							 | 
						|
								    def check_scheduled_alarms(self) -> bool:
							 | 
						|
								        """Check if any alarms are scheduled for the app"""
							 | 
						|
								        self.log("Checking scheduled alarms...")
							 | 
						|
								        result = self.run_adb_command("shell \"dumpsys alarm | grep timesafari\"")
							 | 
						|
								        return result.returncode == 0 and self.package in result.stdout
							 | 
						|
								    
							 | 
						|
								    def run_test(self, test_name: str, test_func, *args, **kwargs) -> TestCase:
							 | 
						|
								        """Run a single test case"""
							 | 
						|
								        self.log(f"Running test: {test_name}")
							 | 
						|
								        start_time = time.time()
							 | 
						|
								        
							 | 
						|
								        try:
							 | 
						|
								            result = test_func(*args, **kwargs)
							 | 
						|
								            duration = time.time() - start_time
							 | 
						|
								            
							 | 
						|
								            if result:
							 | 
						|
								                self.log(f"Test passed: {test_name}", "SUCCESS")
							 | 
						|
								                return TestCase(test_name, "", TestResult.PASS, duration)
							 | 
						|
								            else:
							 | 
						|
								                self.log(f"Test failed: {test_name}", "ERROR")
							 | 
						|
								                return TestCase(test_name, "", TestResult.FAIL, duration, "Test returned False")
							 | 
						|
								                
							 | 
						|
								        except Exception as e:
							 | 
						|
								            duration = time.time() - start_time
							 | 
						|
								            self.log(f"Test error: {test_name} - {str(e)}", "ERROR")
							 | 
						|
								            return TestCase(test_name, "", TestResult.FAIL, duration, str(e))
							 | 
						|
								    
							 | 
						|
								    def run_test_suite(self) -> Dict[str, Any]:
							 | 
						|
								        """Run complete test suite"""
							 | 
						|
								        self.log("🧪 Starting DailyNotification Test Suite")
							 | 
						|
								        self.log("=" * 50)
							 | 
						|
								        
							 | 
						|
								        # Check ADB connection
							 | 
						|
								        result = self.run_adb_command("devices")
							 | 
						|
								        if "device" not in result.stdout:
							 | 
						|
								            self.log("No Android device connected via ADB", "ERROR")
							 | 
						|
								            sys.exit(1)
							 | 
						|
								        
							 | 
						|
								        self.log("ADB device connected", "SUCCESS")
							 | 
						|
								        
							 | 
						|
								        # Test 1: App Launch
							 | 
						|
								        test_case = self.run_test("App Launch", self.launch_app)
							 | 
						|
								        self.test_results.append(test_case)
							 | 
						|
								        
							 | 
						|
								        # Test 2: Background Test
							 | 
						|
								        test_case = self.run_test("Background Operation", self.send_to_background)
							 | 
						|
								        self.test_results.append(test_case)
							 | 
						|
								        
							 | 
						|
								        # Test 3: Force Stop Test
							 | 
						|
								        test_case = self.run_test("Force Stop", self.force_stop_app)
							 | 
						|
								        self.test_results.append(test_case)
							 | 
						|
								        
							 | 
						|
								        # Test 4: Permission Check
							 | 
						|
								        def check_permissions_test():
							 | 
						|
								            permissions = self.check_permissions()
							 | 
						|
								            return any(permissions.values())
							 | 
						|
								        
							 | 
						|
								        test_case = self.run_test("Permission Check", check_permissions_test)
							 | 
						|
								        self.test_results.append(test_case)
							 | 
						|
								        
							 | 
						|
								        # Test 5: Alarm Check
							 | 
						|
								        test_case = self.run_test("Alarm Scheduling", self.check_scheduled_alarms)
							 | 
						|
								        self.test_results.append(test_case)
							 | 
						|
								        
							 | 
						|
								        # Test 6: Notification Test (requires manual scheduling)
							 | 
						|
								        self.log("📱 Manual Notification Test")
							 | 
						|
								        self.log("⚠️  Manual step required: Schedule notification in app", "WARNING")
							 | 
						|
								        input("Press Enter when notification is scheduled...")
							 | 
						|
								        
							 | 
						|
								        test_case = self.run_test("Notification Delivery", self.check_notification_logs, 120)
							 | 
						|
								        self.test_results.append(test_case)
							 | 
						|
								        
							 | 
						|
								        return self.generate_report()
							 | 
						|
								    
							 | 
						|
								    def generate_report(self) -> Dict[str, Any]:
							 | 
						|
								        """Generate test report"""
							 | 
						|
								        total_tests = len(self.test_results)
							 | 
						|
								        passed_tests = sum(1 for test in self.test_results if test.result == TestResult.PASS)
							 | 
						|
								        failed_tests = sum(1 for test in self.test_results if test.result == TestResult.FAIL)
							 | 
						|
								        
							 | 
						|
								        report = {
							 | 
						|
								            "summary": {
							 | 
						|
								                "total": total_tests,
							 | 
						|
								                "passed": passed_tests,
							 | 
						|
								                "failed": failed_tests,
							 | 
						|
								                "success_rate": (passed_tests / total_tests * 100) if total_tests > 0 else 0
							 | 
						|
								            },
							 | 
						|
								            "tests": [
							 | 
						|
								                {
							 | 
						|
								                    "name": test.name,
							 | 
						|
								                    "result": test.result.value,
							 | 
						|
								                    "duration": test.duration,
							 | 
						|
								                    "error": test.error
							 | 
						|
								                }
							 | 
						|
								                for test in self.test_results
							 | 
						|
								            ]
							 | 
						|
								        }
							 | 
						|
								        
							 | 
						|
								        return report
							 | 
						|
								    
							 | 
						|
								    def print_report(self, report: Dict[str, Any]):
							 | 
						|
								        """Print test report"""
							 | 
						|
								        self.log("\n📊 Test Results Summary:")
							 | 
						|
								        self.log("=" * 30)
							 | 
						|
								        
							 | 
						|
								        summary = report["summary"]
							 | 
						|
								        self.log(f"Total Tests: {summary['total']}")
							 | 
						|
								        self.log(f"Passed: {summary['passed']}")
							 | 
						|
								        self.log(f"Failed: {summary['failed']}")
							 | 
						|
								        self.log(f"Success Rate: {summary['success_rate']:.1f}%")
							 | 
						|
								        
							 | 
						|
								        self.log("\nDetailed Results:")
							 | 
						|
								        for test in report["tests"]:
							 | 
						|
								            status = "✅ PASS" if test["result"] == "PASS" else "❌ FAIL"
							 | 
						|
								            duration = f"({test['duration']:.1f}s)"
							 | 
						|
								            self.log(f"{test['name']}: {status} {duration}")
							 | 
						|
								            if test["error"]:
							 | 
						|
								                self.log(f"  Error: {test['error']}", "ERROR")
							 | 
						|
								
							 | 
						|
								def main():
							 | 
						|
								    parser = argparse.ArgumentParser(description="DailyNotification Plugin Test Suite")
							 | 
						|
								    parser.add_argument("-v", "--verbose", action="store_true", help="Enable verbose output")
							 | 
						|
								    parser.add_argument("-p", "--package", default="com.timesafari.dailynotification", help="App package name")
							 | 
						|
								    parser.add_argument("-o", "--output", help="Output report to JSON file")
							 | 
						|
								    parser.add_argument("--timeout", type=int, default=120, help="Test timeout in seconds")
							 | 
						|
								    
							 | 
						|
								    args = parser.parse_args()
							 | 
						|
								    
							 | 
						|
								    tester = DailyNotificationTester(package=args.package, verbose=args.verbose)
							 | 
						|
								    report = tester.run_test_suite()
							 | 
						|
								    tester.print_report(report)
							 | 
						|
								    
							 | 
						|
								    # Save report to file if specified
							 | 
						|
								    if args.output:
							 | 
						|
								        with open(args.output, 'w') as f:
							 | 
						|
								            json.dump(report, f, indent=2)
							 | 
						|
								        tester.log(f"Report saved to: {args.output}")
							 | 
						|
								    
							 | 
						|
								    # Exit with error code if any test failed
							 | 
						|
								    if report["summary"]["failed"] > 0:
							 | 
						|
								        sys.exit(1)
							 | 
						|
								
							 | 
						|
								if __name__ == "__main__":
							 | 
						|
								    main()
							 | 
						|
								
							 |