Files
AIPass/src/aipass/backup/apps/modules/drive_test.py
T
AIOSAIandClaude Opus 4.8 1049bc308b feat(backup): FPLAN-0268 — Google Drive sync pipeline + restore command (restoration Phase 4, final)
Faithful port of GOLD's GoogleDriveSync against the live @api gateway. Completes
the backup restoration (master FPLAN-0264).

Drive pipeline (handlers/drive/):
- DriveClient: folder hierarchy 'AIPass Backups/<project>/', thread-safe cache,
  retry-with-rebuild. Auth via aipass.api get_drive_service + api_call_with_retry
  (never console-OAuth).
- upload.py: resumable MediaFileUpload, 3 threaded workers, single + batch.
- tracker.py: mtime+size dedup (.backup_system/drive_tracker.json) — no re-upload
  of unchanged files.
- test.py: connectivity check.
All 4 drive_* modules un-stubbed. all = snapshot->versioned->drive-sync, drive
step FAILS HONESTLY if creds absent (no silent skip, snapshot+versioned still run).

restore command (modules/restore.py -> handlers/diff/restore.py):
- 'restore <project> list <file>'  (baseline + current + diffs)
- 'restore <project> file <file> <out>'  (reconstruct + write)

pyright/cleanup (Patrick's call): removed backup's standalone pyrightconfig.json
(pre-namespace leftover, archived) so it inherits the repo-root config like every
citizen; dead PyQt5 ui/settings_window.py archived.

Drive tests fully mocked — ZERO real Google calls in CI. Live Drive upload awaits
Google OAuth creds (~/.secrets/aipass/google_client_secret.json + drone @api
reauth google) — Patrick's setup step.

Verified by artifact (devpulse): seedgo 100% all 36 standards / 37 files, 187
tests, ruff clean; restore list/file round-trip confirmed live.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 14:53:42 -07:00

96 lines
2.6 KiB
Python

# =================== AIPass ====================
# Name: drive_test.py
# Description: Drive test module — verifies Google Drive connectivity via @api
# Version: 1.0.0
# Created: 2026-04-17
# Modified: 2026-06-12
# =============================================
"""Drive Test Module — tests Drive auth through @api gateway."""
import sys
from aipass.prax import logger
from aipass.cli.apps.modules import console
from aipass.backup.apps.handlers.json import json_handler
MODULE_NAME = "drive_test"
PRIMARY_COMMAND = "drive-test"
def print_introspection():
"""Display module info and connected handlers."""
console.print(f"[bold cyan]{MODULE_NAME} Module[/bold cyan]")
console.print(f" Primary command: [yellow]{PRIMARY_COMMAND}[/yellow]")
console.print(" Status: Phase 4 -- auth test via @api gateway")
console.print(" Handlers: drive/client, drive/test")
def print_help():
"""Display help for this module."""
print_introspection()
def run_drive_test() -> bool:
"""Test Drive auth through @api gateway.
Creates a DriveClient, authenticates, tests folder access, and
displays results.
Returns:
True if connectivity test passed, False otherwise.
"""
from aipass.backup.apps.handlers.drive.client import DriveClient
from aipass.backup.apps.handlers.drive.test import test_connectivity
client = DriveClient()
result = test_connectivity(client)
if result["success"]:
console.print("[green]Drive connectivity test PASSED[/green]")
console.print(f" Backup folder ID: {result['folder_id']}")
logger.info("[backup] Drive test passed")
else:
console.print(f"[red]Drive connectivity test FAILED: {result['error']}[/red]")
logger.warning(f"[backup] Drive test failed: {result['error']}")
json_handler.log_operation(
"drive_test_complete",
{"success": result["success"]},
)
return result["success"]
def handle_command(command: str, args: list) -> bool:
"""Handle the drive-test command. Returns True if handled."""
if command != PRIMARY_COMMAND:
return False
if not args:
print_introspection()
return True
if args[0] in ("--help", "-h", "help"):
print_help()
return True
if args[0] == "run":
run_drive_test()
return True
# Default: run the test
run_drive_test()
return True
# =============================================
if __name__ == "__main__":
if len(sys.argv) == 1:
print_introspection()
sys.exit(0)
result = handle_command(PRIMARY_COMMAND, sys.argv[1:])
sys.exit(0 if result else 1)