99 lines
3.3 KiB
Python
99 lines
3.3 KiB
Python
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
|