Public Access
Add past project meeting summary tools
PR and Push Build/Test / build-and-test (push) Failing after 10m56s
PR and Push Build/Test / build-and-test (push) Failing after 10m56s
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
using MeetingAssistant.MeetingNotes;
|
||||
using MeetingAssistant.Summary;
|
||||
|
||||
namespace MeetingAssistant.Tests;
|
||||
|
||||
public sealed class PastProjectMeetingSummaryToolTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ListPastProjectMeetingsReturnsPagedSummariesForCurrentMeetingProjects()
|
||||
{
|
||||
var root = CreateRoot();
|
||||
var artifacts = CreateArtifacts(root);
|
||||
var summariesRoot = Path.Combine(root, "Meetings", "Summaries");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(artifacts.MeetingNotePath)!);
|
||||
Directory.CreateDirectory(summariesRoot);
|
||||
await WriteMeetingNoteAsync(artifacts.MeetingNotePath, "Project X", "Project Y");
|
||||
await WriteSummaryAsync(Path.Combine(summariesRoot, "current-summary.md"), "Current", "2026-05-29T09:00:00+02:00", "Project X");
|
||||
await WriteSummaryAsync(Path.Combine(summariesRoot, "project-x-new.md"), "Project X New", "2026-05-28T09:00:00+02:00", "Project X");
|
||||
await WriteSummaryAsync(Path.Combine(summariesRoot, "project-y.md"), "Project Y", "2026-05-27T09:00:00+02:00", "Project Y");
|
||||
await WriteSummaryAsync(Path.Combine(summariesRoot, "project-z.md"), "Project Z", "2026-05-26T09:00:00+02:00", "Project Z");
|
||||
await File.WriteAllTextAsync(Path.Combine(summariesRoot, "not-a-summary.md"), "No frontmatter");
|
||||
artifacts = artifacts with { SummaryPath = Path.Combine(summariesRoot, "current-summary.md") };
|
||||
var tools = CreateTools(artifacts, root);
|
||||
|
||||
var firstPage = await tools.ListPastProjectMeetings(page: 1, page_size: 1);
|
||||
var secondPage = await tools.ListPastProjectMeetings(page: 2, page_size: 1);
|
||||
|
||||
Assert.Contains("page 1/2", firstPage);
|
||||
Assert.Contains("project-x-new.md | 2026-05-28T09:00:00.0000000+02:00 | Project X New | projects: Project X", firstPage);
|
||||
Assert.DoesNotContain("project-y.md", firstPage);
|
||||
Assert.Contains("page 2/2", secondPage);
|
||||
Assert.Contains("project-y.md", secondPage);
|
||||
Assert.DoesNotContain("current-summary.md", firstPage + secondPage);
|
||||
Assert.DoesNotContain("project-z.md", firstPage + secondPage);
|
||||
Assert.DoesNotContain("not-a-summary.md", firstPage + secondPage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListPastProjectMeetingsFiltersAndRejectsOutOfScopeProjects()
|
||||
{
|
||||
var root = CreateRoot();
|
||||
var artifacts = CreateArtifacts(root);
|
||||
var summariesRoot = Path.Combine(root, "Meetings", "Summaries");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(artifacts.MeetingNotePath)!);
|
||||
Directory.CreateDirectory(summariesRoot);
|
||||
await WriteMeetingNoteAsync(artifacts.MeetingNotePath, "Project X", "Project Y");
|
||||
await WriteSummaryAsync(Path.Combine(summariesRoot, "project-x.md"), "Project X", "2026-05-28T09:00:00+02:00", "Project X");
|
||||
await WriteSummaryAsync(Path.Combine(summariesRoot, "project-y.md"), "Project Y", "2026-05-27T09:00:00+02:00", "Project Y");
|
||||
var tools = CreateTools(artifacts, root);
|
||||
|
||||
var projectX = await tools.ListPastProjectMeetings(["Project X"]);
|
||||
var refused = await tools.ListPastProjectMeetings(["Project Z"]);
|
||||
|
||||
Assert.Contains("project-x.md", projectX);
|
||||
Assert.DoesNotContain("project-y.md", projectX);
|
||||
Assert.Equal("Refused: project(s) not assigned to current meeting: Project Z.", refused);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReadPastProjectMeetingSummaryReadsOnlyScopedPastSummaryFiles()
|
||||
{
|
||||
var root = CreateRoot();
|
||||
var artifacts = CreateArtifacts(root);
|
||||
var summariesRoot = Path.Combine(root, "Meetings", "Summaries");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(artifacts.MeetingNotePath)!);
|
||||
Directory.CreateDirectory(summariesRoot);
|
||||
await WriteMeetingNoteAsync(artifacts.MeetingNotePath, "Project X");
|
||||
await WriteSummaryAsync(
|
||||
Path.Combine(summariesRoot, "project-x.md"),
|
||||
"Project X",
|
||||
"2026-05-28T09:00:00+02:00",
|
||||
"Project X",
|
||||
"line one\nline two\nline three");
|
||||
await WriteSummaryAsync(Path.Combine(summariesRoot, "project-z.md"), "Project Z", "2026-05-27T09:00:00+02:00", "Project Z");
|
||||
await WriteSummaryAsync(artifacts.SummaryPath, "Current", "2026-05-29T09:00:00+02:00", "Project X");
|
||||
var outside = Path.Combine(root, "outside.md");
|
||||
await File.WriteAllTextAsync(outside, "outside");
|
||||
var tools = CreateTools(artifacts, root);
|
||||
|
||||
Assert.Equal("line two\nline three", await tools.ReadPastProjectMeetingSummary("project-x.md", from: 9, to: 99));
|
||||
Assert.StartsWith("Refused:", await tools.ReadPastProjectMeetingSummary("project-z.md"));
|
||||
Assert.StartsWith("Refused:", await tools.ReadPastProjectMeetingSummary("current-summary.md"));
|
||||
Assert.StartsWith("Refused:", await tools.ReadPastProjectMeetingSummary(outside));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchIncludesProjectFilesAndScopedPastMeetingSummaries()
|
||||
{
|
||||
var root = CreateRoot();
|
||||
var artifacts = CreateArtifacts(root);
|
||||
var projectsRoot = Path.Combine(root, "Projects");
|
||||
var summariesRoot = Path.Combine(root, "Meetings", "Summaries");
|
||||
Directory.CreateDirectory(Path.Combine(projectsRoot, "Project X"));
|
||||
Directory.CreateDirectory(Path.Combine(projectsRoot, "Project Y"));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(artifacts.MeetingNotePath)!);
|
||||
Directory.CreateDirectory(summariesRoot);
|
||||
await WriteMeetingNoteAsync(artifacts.MeetingNotePath, "Project X", "Project Y");
|
||||
await File.WriteAllTextAsync(Path.Combine(projectsRoot, "Project X", "notes.md"), "alpha project file");
|
||||
await File.WriteAllTextAsync(Path.Combine(projectsRoot, "Project Y", "notes.md"), "alpha other project");
|
||||
await WriteSummaryAsync(Path.Combine(summariesRoot, "project-x.md"), "Project X", "2026-05-28T09:00:00+02:00", "Project X", "alpha past meeting");
|
||||
await WriteSummaryAsync(Path.Combine(summariesRoot, "project-z.md"), "Project Z", "2026-05-27T09:00:00+02:00", "Project Z", "alpha hidden meeting");
|
||||
var tools = CreateTools(artifacts, root);
|
||||
|
||||
var projectX = await tools.Search("alpha", ["Project X"]);
|
||||
var refused = await tools.Search("alpha", ["Project Z"]);
|
||||
|
||||
Assert.Contains("notes.md:1 alpha project file", projectX);
|
||||
Assert.Contains("past-meetings/project-x.md:", projectX);
|
||||
Assert.DoesNotContain("Project Y/notes.md", projectX);
|
||||
Assert.DoesNotContain("project-z.md", projectX);
|
||||
Assert.Equal("Refused: project(s) not assigned to current meeting: Project Z.", refused);
|
||||
}
|
||||
|
||||
private static string CreateRoot()
|
||||
{
|
||||
return Path.Combine(Path.GetTempPath(), "meeting-assistant-tests", Guid.NewGuid().ToString("N"));
|
||||
}
|
||||
|
||||
private static MeetingSessionArtifacts CreateArtifacts(string root)
|
||||
{
|
||||
return new MeetingSessionArtifacts(
|
||||
MeetingNotePath: Path.Combine(root, "Meetings", "Notes", "meeting.md"),
|
||||
TranscriptPath: Path.Combine(root, "Meetings", "Transcripts", "transcript.md"),
|
||||
AssistantContextPath: Path.Combine(root, "Meetings", "Assistant Context", "context.md"),
|
||||
SummaryPath: Path.Combine(root, "Meetings", "Summaries", "current-summary.md"));
|
||||
}
|
||||
|
||||
private static MeetingSummaryTools CreateTools(MeetingSessionArtifacts artifacts, string root)
|
||||
{
|
||||
return new MeetingSummaryTools(
|
||||
artifacts,
|
||||
new MeetingAssistantOptions
|
||||
{
|
||||
Vault =
|
||||
{
|
||||
ProjectsFolder = Path.Combine(root, "Projects"),
|
||||
SummariesFolder = Path.Combine(root, "Meetings", "Summaries")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Task WriteMeetingNoteAsync(string path, params string[] projects)
|
||||
{
|
||||
var projectLines = string.Join('\n', projects.Select(project => $"- {project}"));
|
||||
return File.WriteAllTextAsync(
|
||||
path,
|
||||
$"""
|
||||
---
|
||||
title: Current Meeting
|
||||
projects:
|
||||
{projectLines}
|
||||
---
|
||||
|
||||
Current notes.
|
||||
""");
|
||||
}
|
||||
|
||||
private static Task WriteSummaryAsync(
|
||||
string path,
|
||||
string title,
|
||||
string startTime,
|
||||
string project,
|
||||
string body = "summary body")
|
||||
{
|
||||
return File.WriteAllTextAsync(
|
||||
path,
|
||||
$$"""
|
||||
---
|
||||
title: {{title}}
|
||||
start_time: "{{startTime}}"
|
||||
projects:
|
||||
- {{project}}
|
||||
---
|
||||
|
||||
{{body}}
|
||||
""");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Diagnostics;
|
||||
using MeetingAssistant.Transcription;
|
||||
|
||||
namespace MeetingAssistant.Tests;
|
||||
|
||||
public sealed class ProcessCommandRunnerTests
|
||||
{
|
||||
[Fact]
|
||||
public void CreateStartInfoRunsCliProcessesWithoutVisibleWindows()
|
||||
{
|
||||
var startInfo = ProcessCommandRunner.CreateStartInfo(
|
||||
"docker",
|
||||
["run", "--rm", "meeting-assistant-pyannote:local"],
|
||||
new Dictionary<string, string> { ["HF_TOKEN"] = "token" });
|
||||
|
||||
Assert.False(startInfo.UseShellExecute);
|
||||
Assert.True(startInfo.CreateNoWindow);
|
||||
Assert.Equal(ProcessWindowStyle.Hidden, startInfo.WindowStyle);
|
||||
Assert.True(startInfo.RedirectStandardOutput);
|
||||
Assert.True(startInfo.RedirectStandardError);
|
||||
Assert.Equal("docker", startInfo.FileName);
|
||||
Assert.Equal(["run", "--rm", "meeting-assistant-pyannote:local"], startInfo.ArgumentList);
|
||||
Assert.Equal("token", startInfo.Environment["HF_TOKEN"]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user