import json import types def _configure_paths(monkeypatch, gds, tmp_path): credentials_file = tmp_path / "google_credentials.json" token_file = tmp_path / "google_token.json" legacy_file = tmp_path / "google_token.pickle" credentials_file.write_text("{}", encoding="utf-8") monkeypatch.setattr(gds, "CREDENTIALS_FILE", str(credentials_file)) monkeypatch.setattr(gds, "TOKEN_FILE", str(token_file)) monkeypatch.setattr(gds, "_LEGACY_PICKLE_FILE", str(legacy_file)) return credentials_file, token_file, legacy_file def test_production_runtime_never_starts_interactive_drive_auth(monkeypatch, tmp_path): import services.google_drive_service as gds _configure_paths(monkeypatch, gds, tmp_path) monkeypatch.setenv("GOOGLE_DRIVE_ALLOW_INTERACTIVE_AUTH", "true") monkeypatch.setenv("FLASK_ENV", "production") class ExplodingFlow: @staticmethod def from_client_secrets_file(*_args, **_kwargs): raise AssertionError("browser OAuth must not run in production") monkeypatch.setattr(gds, "InstalledAppFlow", ExplodingFlow) service = gds.GoogleDriveService() assert service.authenticate() is False assert service.last_error_kind == "reauthorization_required" assert "授權檔不存在" in service.last_error def test_drive_auth_readiness_refreshes_and_persists_json_token(monkeypatch, tmp_path): import services.google_drive_service as gds _, token_file, _ = _configure_paths(monkeypatch, gds, tmp_path) token_file.write_text(json.dumps({"token": "old"}), encoding="utf-8") class FakeCredentials: valid = False expired = True refresh_token = "refresh-token" def refresh(self, _request): self.valid = True self.expired = False def to_json(self): return json.dumps({"token": "new-token", "refresh_token": self.refresh_token}) fake_credentials = FakeCredentials() monkeypatch.setattr( gds, "Credentials", types.SimpleNamespace( from_authorized_user_info=lambda _token_data, _scopes: fake_credentials ), ) service = gds.GoogleDriveService() status = service.check_auth_readiness(refresh_expired=True) assert status["ready"] is True assert status["kind"] == "ready" assert service.last_error_kind is None assert json.loads(token_file.read_text(encoding="utf-8"))["token"] == "new-token" def test_drive_auth_readiness_requires_refresh_token(monkeypatch, tmp_path): import services.google_drive_service as gds _, token_file, _ = _configure_paths(monkeypatch, gds, tmp_path) token_file.write_text(json.dumps({"token": "stale"}), encoding="utf-8") class FakeCredentials: valid = False expired = False refresh_token = None monkeypatch.setattr( gds, "Credentials", types.SimpleNamespace( from_authorized_user_info=lambda _token_data, _scopes: FakeCredentials() ), ) service = gds.GoogleDriveService() status = service.check_auth_readiness(refresh_expired=True) assert status["ready"] is False assert status["kind"] == "reauthorization_required" assert service.last_error_kind == "reauthorization_required" assert "缺少可刷新憑證" in service.last_error