Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions DotNet/Admin.BFF/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,20 @@
"Path": "api/facility/{**catch-all}"
}
},
"tenantVendor": {
"ClusterId": "TenantService",
"AuthorizationPolicy": "AuthenticatedUser",
"Match": {
"Path": "api/Vendor/{**catch-all}"
}
},
"tenantVendorVersion": {
"ClusterId": "TenantService",
"AuthorizationPolicy": "AuthenticatedUser",
"Match": {
"Path": "api/VendorVersion/{**catch-all}"
}
},
"route11": {
"ClusterId": "QueryDispatchService",
"AuthorizationPolicy": "AuthenticatedUser",
Expand Down
7 changes: 5 additions & 2 deletions DotNet/Automation.Link/Helpers/FacilitySetupHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ public static async Task EnsureFacilityAsync(
FacilityId = facilityId,
FacilityName = facilityId,
TimeZone = "America/Chicago",
Vendor = Vendor.Epic,
Vendor = new VendorModel
{
Name = "Epic"
},
ScheduledReports = new TenantScheduledReportConfig
{
Monthly = measureIds.ToArray(),
Expand Down Expand Up @@ -109,7 +112,7 @@ public static async Task EnsureNormalizationConfigAsync(
TargetFhirPath = "type[0].coding.code"
},
Description = "Copy Location Identifier to Code",
VendorIds = []
VendorVersionIds = []
});

if (!normResp.IsSuccessStatusCode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,10 @@ private async Task<bool> CreateFacilityViaBffAsync(IAdminBffIntegrationClient ad
FacilityId = facilityId,
FacilityName = facilityId,
TimeZone = "America/Chicago",
Vendor = Vendor.Epic,
Vendor = new VendorModel
{
Name = "Epic"
},
ScheduledReports = new TenantScheduledReportConfig
{
Daily = [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,14 +325,6 @@ public static class NormalizationSteps
public const string SequencesDelete204 = "SEQUENCES DELETE → 204";
public const string SequencesDelete404 = "SEQUENCES DELETE → 404";
public const string SequencesDelete400EmptyFacility = "SEQUENCES DELETE → 400 (empty facility)";
public const string VendorPost201 = "VENDOR POST → 201";
public const string VendorPost409 = "VENDOR POST → 409";
public const string VendorGet200 = "VENDOR GET → 200";
public const string VendorsGet200 = "VENDORS GET → 200";
public const string PresetPost201 = "PRESET POST → 201";
public const string PresetsGet200 = "PRESETS GET → 200";
public const string PresetDelete204 = "PRESET DELETE → 204";
public const string VendorDelete204 = "VENDOR DELETE → 204";
}

public static class QueryDispatchSteps
Expand Down Expand Up @@ -433,6 +425,11 @@ public static class TenantSteps
public const string Restore204 = "Restore → 204";
public const string Restore400NotDeleted = "Restore → 400 (not deleted)";
public const string Restore404NonExistent = "Restore → 404 (non-existent)";
public const string VendorPost201 = "Vendor POST → 201";
public const string VendorPost409 = "Vendor POST → 409";
public const string VendorGet200 = "Vendor GET → 200";
public const string VendorsGet200 = "Vendors GET → 200";
public const string VendorDelete204 = "Vendor DELETE → 204";
public const string Delete204 = "Delete → 204";
public const string Delete404NonExistent = "Delete → 404 (non-existent)";
public const string AdHoc200Seeded = "AdHocReport → 200 (seeded)";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,10 @@ private async Task CreateFacilityAsync(string facilityId, CancellationToken ct)
FacilityId = facilityId,
FacilityName = facilityId,
TimeZone = "America/Chicago",
Vendor = Vendor.Epic,
Vendor = new VendorModel
{
Name = "Epic"
},
ScheduledReports = new TenantScheduledReportConfig { Daily = [], Weekly = [], Monthly = [] }
};
await _facilityClient.CreateAsync(model, ct);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,10 @@ private async Task CreateFacilityAsync(string facilityId, CancellationToken ct)
FacilityId = facilityId,
FacilityName = facilityId,
TimeZone = "America/Chicago",
Vendor = Vendor.Epic,
Vendor = new VendorModel
{
Name = "Epic"
},
ScheduledReports = new TenantScheduledReportConfig { Daily = [], Weekly = [], Monthly = [] }
};
await _facilityClient.CreateAsync(model, ct);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ public override async Task<IReadOnlyList<ApiTestRunResult>> ExecuteAsync(Cancell
var facilityId = $"ApiHealth-Norm-{Guid.NewGuid():N}";
var facilityCreated = false;
var operationCreated = false;
var vendorName = $"ApiHealthVendor-{Guid.NewGuid():N}";
var vendorCreated = false;
Guid? presetId = null;
Guid operationResourceTypeId = Guid.Empty;
var vendorPresetOperationName = $"ApiHealth Vendor Preset Op {Guid.NewGuid():N}";

try
{
Expand All @@ -66,7 +61,7 @@ public override async Task<IReadOnlyList<ApiTestRunResult>> ExecuteAsync(Cancell
TargetFhirPath = "type[0].coding.code"
},
Description = "ApiHealth test — CopyProperty",
VendorIds = []
VendorVersionIds = []
};
var resp = await _client.CreateOperationAsync(request, ct);
if (resp.IsSuccessStatusCode) operationCreated = true;
Expand All @@ -88,7 +83,7 @@ await _client.CreateOperationAsync(new CreateNormalizationOperationRequestApiMod
TargetFhirPath = "type[0].coding.code"
},
Description = "ApiHealth invalid test",
VendorIds = []
VendorVersionIds = []
}, ct), ct: ct));

// POST → 400 (empty resourceTypes)
Expand All @@ -106,7 +101,7 @@ await _client.CreateOperationAsync(new CreateNormalizationOperationRequestApiMod
TargetFhirPath = "type[0].coding.code"
},
Description = "ApiHealth invalid test",
VendorIds = []
VendorVersionIds = []
}, ct), ct: ct));

// GET → 200 (has results)
Expand Down Expand Up @@ -174,143 +169,6 @@ await _client.CreateOperationSequencesAsync(
results.Add(await RunStepAsync(StepNames.SequencesDelete204, 204, async () =>
await _client.DeleteOperationSequencesAsync(facilityId, "Location", ct), ct: ct));

// VENDOR POST → 201
Guid vendorId = Guid.Empty;
results.Add(await RunStepAsync(StepNames.VendorPost201, 201, async () =>
{
var resp = await _client.CreateVendorAsync(vendorName, ct);
if (resp.IsSuccessStatusCode)
{
vendorCreated = true;
vendorId = resp.Body?.Id ?? Guid.Empty;
}
return resp;
}, ct: ct));

// VENDOR POST → 409
results.Add(await RunStepAsync(StepNames.VendorPost409, 409, async () =>
await _client.CreateVendorAsync(vendorName, ct), ct: ct));

// VENDOR GET → 200
results.Add(await RunStepAsync(StepNames.VendorGet200, 200, async () =>
await _client.GetVendorAsync(vendorName, ct), ct: ct));

// VENDORS GET → 200
results.Add(await RunStepAsync(StepNames.VendorsGet200, 200, async () =>
await _client.GetAllVendorsAsync(ct), ct: ct));

// PRESET POST → 201
results.Add(await RunStepAsync(StepNames.PresetPost201, 201, async () =>
{
if (vendorId == Guid.Empty)
{
var v = await _client.GetVendorAsync(vendorName, ct);
vendorId = v.Body?.FirstOrDefault()?.Id ?? Guid.Empty;
}

if (vendorId == Guid.Empty)
{
var vendors = await _client.GetAllVendorsAsync(ct);
vendorId = vendors.Body?.FirstOrDefault(x => string.Equals(x.Name, vendorName, StringComparison.OrdinalIgnoreCase))?.Id ?? Guid.Empty;
}

// Create a vendor-linked operation specifically for preset testing.
// This mirrors the integration test setup and avoids edge-cases where
// deleting presets can cascade differently for non-vendor-linked operations.
await _client.CreateOperationAsync(new CreateNormalizationOperationRequestApiModel
{
ResourceTypes = ["Location"],
FacilityId = facilityId,
Operation = new CreateNormalizationOperationDetailsApiModel
{
OperationType = "CopyProperty",
Name = vendorPresetOperationName,
Description = "Api Health vendor preset operation",
SourceFhirPath = "identifier.value",
TargetFhirPath = "type[0].coding.code"
},
Description = "ApiHealth vendor preset operation",
VendorIds = vendorId == Guid.Empty ? [] : [vendorId.ToString()]
}, ct);

// Operation indexing can lag briefly; poll a few times for the newly created op.
for (var i = 0; i < 8 && operationResourceTypeId == Guid.Empty; i++)
{
var ops = await _client.SearchFacilityOperationsAsync(facilityId, cancellationToken: ct);

operationResourceTypeId = ops.Body?.Records?
.FirstOrDefault(r => string.Equals(r.Name, vendorPresetOperationName, StringComparison.Ordinal))
?.OperationResourceTypes?.FirstOrDefault()?.Id ?? Guid.Empty;

if (operationResourceTypeId == Guid.Empty)
{
operationResourceTypeId = ops.Body?.Records?
.SelectMany(r => r.OperationResourceTypes ?? [])
.Select(rt => rt.Id)
.FirstOrDefault(id => id != Guid.Empty) ?? Guid.Empty;
}

if (operationResourceTypeId == Guid.Empty)
await Task.Delay(250, ct);
}

if (vendorId == Guid.Empty || operationResourceTypeId == Guid.Empty)
throw new InvalidOperationException("Expected vendorId and operationResourceTypeId before creating preset.");

var resp = await _client.CreateVendorPresetAsync(new CreateNormalizationVendorPresetRequestApiModel
{
VendorId = vendorId,
OperationResourceTypeId = operationResourceTypeId
}, ct);

if (resp.IsSuccessStatusCode)
presetId = resp.Body?.Id;

return resp;
}, ct: ct));

// PRESETS GET → 200
results.Add(await RunStepAsync(StepNames.PresetsGet200, 200, async () =>
await _client.GetVendorPresetsAsync(vendorName, cancellationToken: ct), ct: ct));

// PRESET DELETE → 204
// Some deployed environments may still run a Normalization build that throws 500
// when the preset has already been removed as a side effect of operation cleanup.
// Treat that specific legacy error body as success-equivalent delete behavior.
results.Add(await RunStepAsync(StepNames.PresetDelete204, [204, 500], async () =>
{
var presets = await _client.GetVendorPresetsAsync(vendorName, cancellationToken: ct);
var toDelete = presets.Body?.FirstOrDefault(p => operationResourceTypeId == Guid.Empty || p.OperationResourceTypeId == operationResourceTypeId)?.Id
?? presetId
?? Guid.Empty;

if (toDelete == Guid.Empty)
throw new InvalidOperationException("Expected an existing preset id before deleting preset.");

var resp = await _client.DeleteVendorPresetAsync(vendorName, toDelete, ct);
if (resp.StatusCode == 204)
{
presetId = null;
return resp;
}

if (resp.StatusCode == 500 && (resp.RawBody?.Contains("No Vendor Operation Preset exists for the provided id", StringComparison.OrdinalIgnoreCase) ?? false))
{
presetId = null;
return resp;
}

throw new InvalidOperationException($"Expected HTTP 204 but got {resp.StatusCode}.{(resp.RawBody != null ? $" Body: {resp.RawBody}" : "")}");
}, ct: ct));

// VENDOR DELETE → 204
results.Add(await RunStepAsync(StepNames.VendorDelete204, 204, async () =>
{
var resp = await _client.DeleteVendorAsync(vendorName, ct);
if (resp.IsSuccessStatusCode) vendorCreated = false;
return resp;
}, ct: ct));

// DELETE → 204
results.Add(await RunStepAsync(StepNames.Delete204, 204, async () =>
{
Expand All @@ -330,7 +188,7 @@ await _client.CreateOperationAsync(new CreateNormalizationOperationRequestApiMod
TargetFhirPath = "type[0].coding.code"
},
Description = "ApiHealth recovery operation",
VendorIds = []
VendorVersionIds = []
}, ct);
}

Expand All @@ -352,8 +210,6 @@ await _client.CreateOperationAsync(new CreateNormalizationOperationRequestApiMod
}
finally
{
if (presetId is Guid pid && pid != Guid.Empty) await TryCleanupAsync(() => _client.DeleteVendorPresetAsync(vendorName, pid, ct));
if (vendorCreated) await TryCleanupAsync(() => _client.DeleteVendorAsync(vendorName, ct));
if (operationCreated) await TryCleanupAsync(() => _client.DeleteFacilityOperationsAsync(facilityId, ct));
if (facilityCreated) await TryCleanupAsync(() => _facilityClient.DeleteAsync(facilityId, ct));
}
Expand All @@ -368,7 +224,10 @@ private async Task CreateFacilityAsync(string facilityId, CancellationToken ct)
FacilityId = facilityId,
FacilityName = facilityId,
TimeZone = "America/Chicago",
Vendor = Vendor.Epic,
Vendor = new VendorModel
{
Name = "Epic"
},
ScheduledReports = new TenantScheduledReportConfig { Daily = [], Weekly = [], Monthly = [] }
};
await _facilityClient.CreateAsync(model, ct);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,10 @@ private async Task CreateFacilityAsync(string facilityId, CancellationToken ct)
FacilityId = facilityId,
FacilityName = facilityId,
TimeZone = "America/Chicago",
Vendor = Vendor.Epic,
Vendor = new VendorModel
{
Name = "Epic"
},
ScheduledReports = new TenantScheduledReportConfig { Daily = [], Weekly = [], Monthly = [] }
};
await _facilityClient.CreateAsync(model, ct);
Expand Down
Loading
Loading