feat(cv-qa): map missing records from reviewed source evidence
This commit is contained in:
@@ -72,6 +72,85 @@ public class CvImportReviewedPersistenceTests
|
||||
return run;
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task Source_mapped_new_records_fill_empty_profile_or_roll_back_without_rejected_proposals(bool succeeds)
|
||||
{
|
||||
await using var database = await MariaDbDatabase.CreateAsync();
|
||||
await using var db = database.Context();
|
||||
var run = await Seed(db);
|
||||
var blocks = new List<CvImportBlock>();
|
||||
var sequence = 0;
|
||||
CvImportRecordMapping Map(string category, params (string Name, string Value)[] values)
|
||||
{
|
||||
var fields = values.Select(value =>
|
||||
{
|
||||
var block = new CvImportBlock("b" + ++sequence, value.Value, "paragraph", 1);
|
||||
blocks.Add(block);
|
||||
return new CvImportMappedField(value.Name, value.Value, block.Id);
|
||||
}).ToArray();
|
||||
return new("record-" + sequence, category, null, fields);
|
||||
}
|
||||
var mappings = new[]
|
||||
{
|
||||
Map("contact", ("fullName", "Åse Synthetic"), ("email", "ase@example.test"), ("phone", "+47 400 00 001"), ("headline", "Engineer"), ("location", "Oslo"), ("website", "https://example.test"), ("linkedIn", "https://linkedin.com/in/synthetic"), ("gitHub", "https://github.com/synthetic"), ("linkLabel", "Portfolio"), ("linkUrl", "https://portfolio.example.test")),
|
||||
Map("jobs", ("title", "Engineer"), ("company", "First AS"), ("location", "Oslo"), ("start", "2018"), ("end", "2020"), ("bullets", "Built tools."), ("skills", "Rust")),
|
||||
Map("jobs", ("title", "Lead"), ("company", "Second AS"), ("start", "2021"), ("end", "Present"), ("isCurrent", "true"), ("bullets", "Led delivery.")),
|
||||
Map("education", ("qualification", "Bachelor"), ("qualificationLevel", "Bachelor"), ("institution", "First University"), ("location", "Bergen"), ("start", "2010"), ("end", "2013"), ("details", "Databases")),
|
||||
Map("education", ("qualification", "Master"), ("institution", "Second University"), ("start", "2013"), ("end", "2015"), ("details", "Distributed systems")),
|
||||
Map("certifications", ("name", "Synthetic certificate"), ("issuer", "Example Institute"), ("date", "2022"), ("location", "Online"), ("details", "Recorded assessment")),
|
||||
Map("projects", ("name", "Atlas"), ("role", "Developer"), ("location", "Remote"), ("start", "2020"), ("end", "2021"), ("bullets", "Built search."), ("skills", "React")),
|
||||
Map("languages", ("name", "Norsk"), ("level", "Morsmål"), ("notes", "Stated level")), Map("languages", ("name", "English")),
|
||||
Map("skills", ("value", "Rust"), ("value", "Python")), Map("summary", ("value", "Source-backed professional summary.")),
|
||||
Map("otherSections", ("title", "Courses"), ("items", "Systems course")), Map("awards", ("value", "Synthetic award")),
|
||||
Map("publications", ("value", "Synthetic publication")), Map("organisations", ("value", "Synthetic organisation")),
|
||||
Map("interests", ("value", "Hiking")), Map("references", ("value", "Available on request")),
|
||||
};
|
||||
run.RawExtractedText = string.Join('\n', blocks.Select(b => b.Text));
|
||||
run.DocumentJson = JsonSerializer.Serialize(new CvImportDocument(run.RawExtractedText, false, "application/pdf", 1, run.RawExtractedText.Length, "synthetic.pdf", blocks, Array.Empty<string>(), "synthetic-test-document"));
|
||||
run.Artifact = new() { OwnerUserId = Owner, OriginalFileName = "synthetic.pdf", StoredFileName = "synthetic.pdf", MimeType = "application/pdf", Sha256 = new string('a', 64) };
|
||||
await db.SaveChangesAsync();
|
||||
var artifactId = run.ArtifactId;
|
||||
var request = new ProfileCvController.ApplyReviewedRequest(0, new[] { new CvImportDecision("skills.0", "keep"), new CvImportDecision("skills.1", "keep") }, mappings);
|
||||
var result = await Controller(db, succeeds).ApplyReviewed(run.Id, request);
|
||||
if (succeeds)
|
||||
{
|
||||
Assert.IsType<OkObjectResult>(result);
|
||||
Assert.IsType<OkObjectResult>(await Controller(db).ApplyReviewed(run.Id, request));
|
||||
}
|
||||
else Assert.IsType<BadRequestObjectResult>(result);
|
||||
await db.SaveChangesAsync();
|
||||
await using var verify = database.Context();
|
||||
var snapshot = await new CareerProfileService(verify).LoadSnapshotAsync(Owner, default);
|
||||
Assert.Equal(succeeds ? 1 : 0, snapshot.Revision);
|
||||
Assert.Equal(succeeds ? 2 : 0, await verify.CareerExperiences.CountAsync());
|
||||
Assert.Equal(succeeds ? 2 : 0, await verify.CareerEducations.CountAsync());
|
||||
Assert.Equal(succeeds ? 2 : 0, await verify.CareerLanguages.CountAsync());
|
||||
Assert.Equal(succeeds ? 1 : 0, await verify.CareerProjects.CountAsync());
|
||||
Assert.Equal(succeeds ? 1 : 0, await verify.CareerCertifications.CountAsync());
|
||||
Assert.Equal(succeeds ? new[] { "Python", "Rust" } : Array.Empty<string>(), await verify.CareerSkills.OrderBy(s => s.Name).Select(s => s.Name!).ToArrayAsync());
|
||||
Assert.Equal(succeeds ? 1 : 0, await verify.CareerProfileVersions.CountAsync());
|
||||
Assert.Equal(succeeds ? "applied" : "pending_review", (await verify.CvExtractionRuns.SingleAsync()).Status);
|
||||
if (!succeeds) return;
|
||||
var profile = snapshot.Profile;
|
||||
Assert.Equal("Åse Synthetic", profile.Contact.FullName);
|
||||
Assert.Equal("https://portfolio.example.test", Assert.Single(profile.Contact.Links).Url);
|
||||
Assert.Equal("2018", profile.Jobs[0].Start);
|
||||
Assert.Equal("Oslo", profile.Jobs[0].Location);
|
||||
Assert.True(profile.Jobs[1].IsCurrent);
|
||||
Assert.Null(profile.Languages.Single(l => l.Name == "English").Level);
|
||||
Assert.Equal("Databases", Assert.Single(profile.Education[0].Details));
|
||||
Assert.Equal("React", Assert.Single(profile.Projects[0].Skills));
|
||||
Assert.Equal("Courses", Assert.Single(profile.OtherSections).Title);
|
||||
Assert.Single(profile.Awards); Assert.Single(profile.Publications); Assert.Single(profile.Organisations); Assert.Single(profile.Interests); Assert.Single(profile.References); Assert.Single(profile.Summary);
|
||||
Assert.DoesNotContain("SQL", StructuredCvProfileJson.SerializePersisted(profile));
|
||||
Assert.Equal(artifactId, profile.Metadata.Fields["jobs.0.title"].SourceArtifactId);
|
||||
Assert.Equal(run.Id, profile.Metadata.Fields["jobs.0.title"].SourceExtractionRunId);
|
||||
Assert.Equal("user-source-mapping", profile.Metadata.Fields["jobs.0.title"].Method);
|
||||
Assert.Contains("Mappings", (await verify.CvExtractionRuns.SingleAsync()).ReviewJson);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
|
||||
Reference in New Issue
Block a user