test(teams-pipeline): cover quoted-user Graph @odata.id paths
Lock in users('{id}')/onlineMeetings('{id}') parsing, job creation from that
notification shape, and replay that re-reads a stored transcript id.
This commit is contained in:
@@ -444,6 +444,28 @@ def test_parse_graph_meeting_resource_reads_quoted_users_transcript_path():
|
||||
assert parsed["recording_id"] is None
|
||||
|
||||
|
||||
def test_parse_graph_meeting_resource_reads_quoted_user_key_odata_id():
|
||||
parsed = parse_graph_meeting_resource(
|
||||
"users('org-1')/onlineMeetings('MSo-meeting')/transcripts('ktViz-transcript-TranscriptV2=')"
|
||||
)
|
||||
|
||||
assert parsed["organizer_user_id"] == "org-1"
|
||||
assert parsed["meeting_id"] == "MSo-meeting"
|
||||
assert parsed["transcript_id"] == "ktViz-transcript-TranscriptV2="
|
||||
assert parsed["recording_id"] is None
|
||||
|
||||
|
||||
def test_parse_graph_meeting_resource_reads_graph_url_quoted_user_key():
|
||||
parsed = parse_graph_meeting_resource(
|
||||
"https://graph.microsoft.com/v1.0/users('org-1')/onlineMeetings('MSo-meeting')"
|
||||
"/transcripts('tx-1')"
|
||||
)
|
||||
|
||||
assert parsed["organizer_user_id"] == "org-1"
|
||||
assert parsed["meeting_id"] == "MSo-meeting"
|
||||
assert parsed["transcript_id"] == "tx-1"
|
||||
|
||||
|
||||
def test_parse_graph_meeting_resource_ignores_get_all_transcripts_sentinel():
|
||||
parsed = parse_graph_meeting_resource("communications/onlineMeetings/getAllTranscripts")
|
||||
|
||||
@@ -508,6 +530,106 @@ def test_create_job_from_get_all_transcripts_uses_meeting_id_not_transcript_id(t
|
||||
assert job.meeting_ref.metadata.get("transcript_id") == transcript_id
|
||||
|
||||
|
||||
def test_create_job_from_quoted_user_odata_id_uses_meeting_id_not_transcript_id(tmp_path):
|
||||
store = TeamsPipelineStore(tmp_path / "teams-store.json")
|
||||
pipeline = TeamsMeetingPipeline(graph_client=FakeGraphClient(), store=store)
|
||||
transcript_id = "ktVizInGAAAAi_B6lATZRTE5Om1lZXRpbmdfTranscriptV2="
|
||||
|
||||
job = pipeline.create_job_from_notification(
|
||||
{
|
||||
"id": "notif-quoted-user",
|
||||
"changeType": "created",
|
||||
"resource": "communications/onlineMeetings/getAllTranscripts",
|
||||
"resourceData": {
|
||||
"id": transcript_id,
|
||||
"@odata.type": "#Microsoft.Graph.callTranscript",
|
||||
"@odata.id": (
|
||||
"users('976f4b31-fd01-4e0b-9178-29cc40c14438')"
|
||||
f"/onlineMeetings('MSo-meeting-id')/transcripts('{transcript_id}')"
|
||||
),
|
||||
},
|
||||
"tenantId": "tenant-1",
|
||||
}
|
||||
)
|
||||
|
||||
assert job.meeting_ref is not None
|
||||
assert job.meeting_ref.meeting_id == "MSo-meeting-id"
|
||||
assert job.meeting_ref.organizer_user_id == "976f4b31-fd01-4e0b-9178-29cc40c14438"
|
||||
assert job.meeting_ref.meeting_id != transcript_id
|
||||
assert job.meeting_ref.metadata.get("transcript_id") == transcript_id
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_run_job_reparses_quoted_user_odata_id_when_stored_meeting_id_is_transcript(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
from plugins.teams_pipeline import pipeline as pipeline_module
|
||||
from plugins.teams_pipeline.models import TeamsMeetingRef
|
||||
|
||||
captured: dict[str, str | None] = {}
|
||||
|
||||
async def _resolve(client, *, meeting_id=None, join_web_url=None, tenant_id=None, organizer_user_id=None):
|
||||
captured["meeting_id"] = meeting_id
|
||||
captured["organizer_user_id"] = organizer_user_id
|
||||
return TeamsMeetingRef(
|
||||
meeting_id=str(meeting_id),
|
||||
organizer_user_id=organizer_user_id,
|
||||
tenant_id=tenant_id,
|
||||
metadata={"subject": "Standup"},
|
||||
)
|
||||
|
||||
async def _fetch_transcript(client, meeting_ref):
|
||||
return (
|
||||
MeetingArtifact(artifact_type="transcript", artifact_id="tx-1", display_name="meeting.vtt"),
|
||||
"Decision: Re-parse stored Graph notifications on replay.\nAction: Confirm the meeting id is used.",
|
||||
)
|
||||
|
||||
async def _summarize(**kwargs):
|
||||
return pipeline_module.TeamsMeetingSummaryPayload(
|
||||
meeting_ref=kwargs["resolved_meeting"],
|
||||
title="Standup",
|
||||
transcript_text=kwargs["transcript_text"],
|
||||
summary="Reparsed",
|
||||
source_artifacts=kwargs["artifacts"],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(pipeline_module, "resolve_meeting_reference", _resolve)
|
||||
monkeypatch.setattr(pipeline_module, "fetch_preferred_transcript_text", _fetch_transcript)
|
||||
monkeypatch.setattr(pipeline_module, "enrich_meeting_with_call_record", _no_call_record)
|
||||
|
||||
store = TeamsPipelineStore(tmp_path / "teams-store.json")
|
||||
pipeline = TeamsMeetingPipeline(
|
||||
graph_client=FakeGraphClient(),
|
||||
store=store,
|
||||
config={"transcript_min_chars": 20},
|
||||
summarize_fn=_summarize,
|
||||
)
|
||||
transcript_id = "ktVizInGAAAAi_B6lATZRTE5Om1lZXRpbmdfTranscriptV2="
|
||||
notification = {
|
||||
"id": "notif-replay",
|
||||
"changeType": "created",
|
||||
"resource": "communications/onlineMeetings/getAllTranscripts",
|
||||
"resourceData": {
|
||||
"id": transcript_id,
|
||||
"@odata.type": "#Microsoft.Graph.callTranscript",
|
||||
"@odata.id": (
|
||||
"users('org-1')/onlineMeetings('MSo-from-odata')/transcripts("
|
||||
f"'{transcript_id}')"
|
||||
),
|
||||
},
|
||||
}
|
||||
job = pipeline.create_job_from_notification(notification)
|
||||
assert job.meeting_ref is not None
|
||||
job.meeting_ref.meeting_id = transcript_id
|
||||
store.upsert_job(job.job_id, job.to_dict())
|
||||
|
||||
ran = await pipeline.run_job(job.job_id)
|
||||
|
||||
assert captured["meeting_id"] == "MSo-from-odata"
|
||||
assert captured["organizer_user_id"] == "org-1"
|
||||
assert ran.status == "completed"
|
||||
|
||||
|
||||
def test_create_job_from_users_resource_path_without_odata_id(tmp_path):
|
||||
store = TeamsPipelineStore(tmp_path / "teams-store.json")
|
||||
pipeline = TeamsMeetingPipeline(graph_client=FakeGraphClient(), store=store)
|
||||
|
||||
Reference in New Issue
Block a user