Files
server/test/Api.Test/Dirt/OrganizationReportsControllerTests.cs

1438 lines
52 KiB
C#

using Bit.Api.Dirt.Controllers;
using Bit.Api.Dirt.Models.Request;
using Bit.Api.Dirt.Models.Response;
using Bit.Core;
using Bit.Core.Context;
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Models.Data;
using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
using Bit.Core.Dirt.Reports.Services;
using Bit.Core.Dirt.Repositories;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using Xunit;
using ZiggyCreatures.Caching.Fusion;
namespace Bit.Api.Test.Dirt;
[ControllerCustomize(typeof(OrganizationReportsController))]
[SutProviderCustomize]
public class OrganizationReportControllerTests
{
// GetLatestOrganizationReportAsync
[Theory, BitAutoData]
public async Task GetLatestOrganizationReportAsync_WithValidatedFile_ReturnsOkWithDownloadUrl(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport expectedReport,
string downloadUrl)
{
// Arrange
var reportFile = new ReportFile { Id = "file-id", FileName = "report.json", Size = 1024, Validated = true };
expectedReport.SetReportFile(reportFile);
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AccessIntelligenceVersion2)
.Returns(true);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetLatestOrganizationReportAsync(orgId)
.Returns(expectedReport);
sutProvider.GetDependency<IOrganizationReportStorageService>()
.GetReportDataDownloadUrlAsync(expectedReport, Arg.Any<ReportFile>())
.Returns(downloadUrl);
sutProvider.GetDependency<IOrganizationReportStorageService>()
.FileUploadType
.Returns(FileUploadType.Azure);
// Act
var result = await sutProvider.Sut.GetLatestOrganizationReportAsync(orgId);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var response = Assert.IsType<OrganizationReportResponseModel>(okResult.Value);
Assert.Equal(downloadUrl, response.ReportFileDownloadUrl);
Assert.Equal(FileUploadType.Azure, response.FileUploadType);
}
[Theory, BitAutoData]
public async Task GetLatestOrganizationReportAsync_WithNoFile_ReturnsOkWithNullDownloadUrl(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport expectedReport)
{
// Arrange
expectedReport.ReportFile = null;
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetLatestOrganizationReportAsync(orgId)
.Returns(expectedReport);
// Act
var result = await sutProvider.Sut.GetLatestOrganizationReportAsync(orgId);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var response = Assert.IsType<OrganizationReportResponseModel>(okResult.Value);
Assert.Null(response.ReportFileDownloadUrl);
Assert.Null(response.FileUploadType);
}
[Theory, BitAutoData]
public async Task GetLatestOrganizationReportAsync_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId)
{
// Arrange
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.GetLatestOrganizationReportAsync(orgId));
await sutProvider.GetDependency<IGetOrganizationReportQuery>()
.DidNotReceive()
.GetLatestOrganizationReportAsync(Arg.Any<Guid>());
}
// TODO: Re-enable in PM-37469 when UseRiskInsights access control is restored
// [Theory, BitAutoData]
// public async Task GetLatestOrganizationReportAsync_NoUseRiskInsights_ThrowsBadRequestException(
// SutProvider<OrganizationReportsController> sutProvider,
// Guid orgId)
// {
// // Arrange
// sutProvider.GetDependency<ICurrentContext>()
// .AccessReports(orgId)
// .Returns(true);
//
// sutProvider.GetDependency<IApplicationCacheService>()
// .GetOrganizationAbilityAsync(orgId)
// .Returns(new OrganizationAbility { UseRiskInsights = false });
//
// // Act & Assert
// await Assert.ThrowsAsync<BadRequestException>(() =>
// sutProvider.Sut.GetLatestOrganizationReportAsync(orgId));
//
// await sutProvider.GetDependency<IGetOrganizationReportQuery>()
// .DidNotReceive()
// .GetLatestOrganizationReportAsync(Arg.Any<Guid>());
// }
// CreateOrganizationReportAsync - V1 (flag off)
[Theory, BitAutoData]
public async Task CreateOrganizationReportAsync_V1_WithValidRequest_ReturnsOkResult(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
AddOrganizationReportRequestModel request,
OrganizationReport expectedReport)
{
// Arrange
expectedReport.ReportFile = null;
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AccessIntelligenceVersion2)
.Returns(false);
sutProvider.GetDependency<IAddOrganizationReportCommand>()
.AddOrganizationReportAsync(Arg.Any<AddOrganizationReportRequest>())
.Returns(expectedReport);
// Act
var result = await sutProvider.Sut.CreateOrganizationReportAsync(orgId, request);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var expectedResponse = new OrganizationReportResponseModel(expectedReport);
Assert.Equivalent(expectedResponse, okResult.Value);
}
[Theory, BitAutoData]
public async Task CreateOrganizationReportAsync_V1_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
AddOrganizationReportRequestModel request)
{
// Arrange
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AccessIntelligenceVersion2)
.Returns(false);
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.CreateOrganizationReportAsync(orgId, request));
await sutProvider.GetDependency<IAddOrganizationReportCommand>()
.DidNotReceive()
.AddOrganizationReportAsync(Arg.Any<AddOrganizationReportRequest>());
}
// CreateOrganizationReportAsync - V2 (flag on)
[Theory, BitAutoData]
public async Task CreateOrganizationReportAsync_V2_WithValidRequest_ReturnsFileResponseModel(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
AddOrganizationReportRequestModel request,
OrganizationReport expectedReport,
string uploadUrl)
{
// Arrange
request.FileSize = 1024;
var reportFile = new ReportFile { Id = "file-id", FileName = "report.json", Size = 1024, Validated = false };
expectedReport.SetReportFile(reportFile);
SetupV2Authorization(sutProvider, orgId);
sutProvider.GetDependency<ICreateOrganizationReportCommand>()
.CreateAsync(Arg.Any<AddOrganizationReportRequest>())
.Returns(expectedReport);
sutProvider.GetDependency<IOrganizationReportStorageService>()
.GetReportFileUploadUrlAsync(expectedReport, Arg.Any<ReportFile>())
.Returns(uploadUrl);
sutProvider.GetDependency<IOrganizationReportStorageService>()
.FileUploadType
.Returns(FileUploadType.Azure);
// Act
var result = await sutProvider.Sut.CreateOrganizationReportAsync(orgId, request);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var response = Assert.IsType<OrganizationReportFileResponseModel>(okResult.Value);
Assert.Equal(uploadUrl, response.ReportFileUploadUrl);
Assert.Equal(FileUploadType.Azure, response.FileUploadType);
Assert.NotNull(response.ReportResponse);
}
[Theory, BitAutoData]
public async Task CreateOrganizationReportAsync_V2_EmptyOrgId_ThrowsBadRequestException(
SutProvider<OrganizationReportsController> sutProvider,
AddOrganizationReportRequestModel request)
{
// Arrange
var emptyOrgId = Guid.Empty;
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AccessIntelligenceVersion2)
.Returns(true);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.CreateOrganizationReportAsync(emptyOrgId, request));
Assert.Equal("OrganizationId is required.", exception.Message);
}
[Theory, BitAutoData]
public async Task CreateOrganizationReportAsync_V2_MissingFileSize_ThrowsBadRequestException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
AddOrganizationReportRequestModel request)
{
// Arrange
request.FileSize = null;
SetupV2Authorization(sutProvider, orgId);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.CreateOrganizationReportAsync(orgId, request));
Assert.Equal("File size is required.", exception.Message);
}
[Theory, BitAutoData]
public async Task CreateOrganizationReportAsync_V2_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
AddOrganizationReportRequestModel request)
{
// Arrange
request.FileSize = 1024;
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AccessIntelligenceVersion2)
.Returns(true);
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.CreateOrganizationReportAsync(orgId, request));
await sutProvider.GetDependency<ICreateOrganizationReportCommand>()
.DidNotReceive()
.CreateAsync(Arg.Any<AddOrganizationReportRequest>());
}
// GetOrganizationReportAsync
[Theory, BitAutoData]
public async Task GetOrganizationReportAsync_WithValidatedFile_ReturnsOkWithDownloadUrl(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
OrganizationReport expectedReport,
string downloadUrl)
{
// Arrange
expectedReport.OrganizationId = orgId;
var reportFile = new ReportFile { Id = "file-id", FileName = "report.json", Size = 1024, Validated = true };
expectedReport.SetReportFile(reportFile);
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(reportId)
.Returns(expectedReport);
sutProvider.GetDependency<IOrganizationReportStorageService>()
.GetReportDataDownloadUrlAsync(expectedReport, Arg.Any<ReportFile>())
.Returns(downloadUrl);
sutProvider.GetDependency<IOrganizationReportStorageService>()
.FileUploadType
.Returns(FileUploadType.Azure);
// Act
var result = await sutProvider.Sut.GetOrganizationReportAsync(orgId, reportId);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var response = Assert.IsType<OrganizationReportResponseModel>(okResult.Value);
Assert.Equal(downloadUrl, response.ReportFileDownloadUrl);
Assert.Equal(FileUploadType.Azure, response.FileUploadType);
}
[Theory, BitAutoData]
public async Task GetOrganizationReportAsync_WithNoFile_ReturnsOkWithoutDownloadUrl(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
OrganizationReport expectedReport)
{
// Arrange
expectedReport.OrganizationId = orgId;
expectedReport.ReportFile = null;
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(reportId)
.Returns(expectedReport);
// Act
var result = await sutProvider.Sut.GetOrganizationReportAsync(orgId, reportId);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var response = Assert.IsType<OrganizationReportResponseModel>(okResult.Value);
Assert.Null(response.ReportFileDownloadUrl);
Assert.Null(response.FileUploadType);
}
[Theory, BitAutoData]
public async Task GetOrganizationReportAsync_WithOrgMismatch_ThrowsBadRequestException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
OrganizationReport expectedReport)
{
// Arrange
expectedReport.OrganizationId = Guid.NewGuid();
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(reportId)
.Returns(expectedReport);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.GetOrganizationReportAsync(orgId, reportId));
Assert.Equal("Invalid report ID", exception.Message);
}
[Theory, BitAutoData]
public async Task GetOrganizationReportAsync_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId)
{
// Arrange
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.GetOrganizationReportAsync(orgId, reportId));
await sutProvider.GetDependency<IGetOrganizationReportQuery>()
.DidNotReceive()
.GetOrganizationReportAsync(Arg.Any<Guid>());
}
// DeleteOrganizationReportAsync
[Theory, BitAutoData]
public async Task DeleteOrganizationReportAsync_WithFile_DeletesDbThenStorage(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
var reportFile = new ReportFile { Id = "file-id", FileName = "report.json", Size = 1024, Validated = true };
report.OrganizationId = orgId;
report.SetReportFile(reportFile);
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
// Act
await sutProvider.Sut.DeleteOrganizationReportAsync(orgId, report.Id);
// Assert
await sutProvider.GetDependency<IOrganizationReportRepository>()
.Received(1)
.DeleteAsync(report);
await sutProvider.GetDependency<IOrganizationReportStorageService>()
.Received(1)
.DeleteReportFilesAsync(report, "file-id");
await sutProvider.GetDependency<IFusionCache>()
.Received(1)
.RemoveByTagAsync(
OrganizationReportCacheConstants.BuildCacheTagForOrganizationReports(orgId));
}
[Theory, BitAutoData]
public async Task DeleteOrganizationReportAsync_WithNoFile_DeletesDbOnly(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
report.OrganizationId = orgId;
report.ReportFile = null;
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
// Act
await sutProvider.Sut.DeleteOrganizationReportAsync(orgId, report.Id);
// Assert
await sutProvider.GetDependency<IOrganizationReportRepository>()
.Received(1)
.DeleteAsync(report);
await sutProvider.GetDependency<IOrganizationReportStorageService>()
.DidNotReceive()
.DeleteReportFilesAsync(Arg.Any<OrganizationReport>(), Arg.Any<string>());
await sutProvider.GetDependency<IFusionCache>()
.Received(1)
.RemoveByTagAsync(
OrganizationReportCacheConstants.BuildCacheTagForOrganizationReports(orgId));
}
[Theory, BitAutoData]
public async Task DeleteOrganizationReportAsync_ReportNotFound_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId)
{
// Arrange
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(reportId)
.Throws(new NotFoundException());
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.DeleteOrganizationReportAsync(orgId, reportId));
}
[Theory, BitAutoData]
public async Task DeleteOrganizationReportAsync_OrgMismatch_ThrowsBadRequestException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
report.OrganizationId = Guid.NewGuid();
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.DeleteOrganizationReportAsync(orgId, report.Id));
Assert.Equal("Invalid report ID", exception.Message);
await sutProvider.GetDependency<IOrganizationReportRepository>()
.DidNotReceive()
.DeleteAsync(Arg.Any<OrganizationReport>());
}
[Theory, BitAutoData]
public async Task DeleteOrganizationReportAsync_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId)
{
// Arrange
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.DeleteOrganizationReportAsync(orgId, reportId));
await sutProvider.GetDependency<IOrganizationReportRepository>()
.DidNotReceive()
.DeleteAsync(Arg.Any<OrganizationReport>());
}
// RenewFileUploadUrlAsync
[Theory, BitAutoData]
public async Task RenewFileUploadUrlAsync_WithUnvalidatedFile_ReturnsRenewedUrl(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report,
string uploadUrl)
{
// Arrange
var reportFile = new ReportFile { Id = "file-id", FileName = "report.json", Size = 1024, Validated = false };
report.OrganizationId = orgId;
report.SetReportFile(reportFile);
SetupV2Authorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
sutProvider.GetDependency<IOrganizationReportStorageService>()
.GetReportFileUploadUrlAsync(report, Arg.Any<ReportFile>())
.Returns(uploadUrl);
sutProvider.GetDependency<IOrganizationReportStorageService>()
.FileUploadType
.Returns(FileUploadType.Azure);
// Act
var result = await sutProvider.Sut.RenewFileUploadUrlAsync(orgId, report.Id, "file-id");
// Assert
Assert.Equal(uploadUrl, result.ReportFileUploadUrl);
Assert.Equal(FileUploadType.Azure, result.FileUploadType);
Assert.NotNull(result.ReportResponse);
}
[Theory, BitAutoData]
public async Task RenewFileUploadUrlAsync_ReportNotFound_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId)
{
// Arrange
SetupV2Authorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(reportId)
.Throws(new NotFoundException());
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.RenewFileUploadUrlAsync(orgId, reportId, "file-id"));
}
[Theory, BitAutoData]
public async Task RenewFileUploadUrlAsync_OrgMismatch_ThrowsBadRequestException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
report.OrganizationId = Guid.NewGuid();
SetupV2Authorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.RenewFileUploadUrlAsync(orgId, report.Id, "file-id"));
Assert.Equal("Invalid report ID", exception.Message);
}
[Theory, BitAutoData]
public async Task RenewFileUploadUrlAsync_FileAlreadyValidated_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
var reportFile = new ReportFile { Id = "file-id", FileName = "report.json", Size = 1024, Validated = true };
report.OrganizationId = orgId;
report.SetReportFile(reportFile);
SetupV2Authorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.RenewFileUploadUrlAsync(orgId, report.Id, "file-id"));
}
[Theory, BitAutoData]
public async Task RenewFileUploadUrlAsync_NoFileData_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
report.OrganizationId = orgId;
report.ReportFile = null;
SetupV2Authorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.RenewFileUploadUrlAsync(orgId, report.Id, "file-id"));
}
[Theory, BitAutoData]
public async Task RenewFileUploadUrlAsync_MismatchedFileId_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
var reportFile = new ReportFile { Id = "file-id", FileName = "report.json", Size = 1024, Validated = false };
report.OrganizationId = orgId;
report.SetReportFile(reportFile);
SetupV2Authorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.RenewFileUploadUrlAsync(orgId, report.Id, "wrong-file-id"));
}
[Theory, BitAutoData]
public async Task RenewFileUploadUrlAsync_NullReportFileId_ThrowsBadRequestException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId)
{
// Arrange
var report = new OrganizationReport { OrganizationId = orgId };
SetupV2Authorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(reportId)
.Returns(report);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.RenewFileUploadUrlAsync(orgId, reportId, null));
Assert.Equal("ReportFileId is required.", exception.Message);
}
[Theory, BitAutoData]
public async Task RenewFileUploadUrlAsync_EmptyReportFileId_ThrowsBadRequestException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId)
{
// Arrange
var report = new OrganizationReport { OrganizationId = orgId };
SetupV2Authorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(reportId)
.Returns(report);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.RenewFileUploadUrlAsync(orgId, reportId, string.Empty));
Assert.Equal("ReportFileId is required.", exception.Message);
}
[Theory, BitAutoData]
public async Task DeleteOrganizationReportAsync_StorageFailure_StillCompletesWithoutThrowing(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
var reportFile = new ReportFile { Id = "file-id", FileName = "report.json", Size = 1024, Validated = true };
report.OrganizationId = orgId;
report.SetReportFile(reportFile);
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
sutProvider.GetDependency<IOrganizationReportStorageService>()
.DeleteReportFilesAsync(report, "file-id")
.ThrowsAsync(new Exception("Azure storage unavailable"));
// Act — should not throw despite storage failure
await sutProvider.Sut.DeleteOrganizationReportAsync(orgId, report.Id);
// Assert — DB delete and cache invalidation still happened
await sutProvider.GetDependency<IOrganizationReportRepository>()
.Received(1)
.DeleteAsync(report);
await sutProvider.GetDependency<IFusionCache>()
.Received(1)
.RemoveByTagAsync(
OrganizationReportCacheConstants.BuildCacheTagForOrganizationReports(orgId));
sutProvider.GetDependency<ILogger<OrganizationReportsController>>()
.Received(1)
.Log(
LogLevel.Warning,
Arg.Any<EventId>(),
Arg.Any<object>(),
Arg.Any<Exception>(),
Arg.Any<Func<object, Exception?, string>>());
}
// UpdateOrganizationReportAsync
[Theory, BitAutoData]
public async Task UpdateOrganizationReportAsync_ReturnsReportResponseModel(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
UpdateOrganizationReportV2RequestModel request,
OrganizationReport expectedReport)
{
// Arrange
expectedReport.ReportFile = null;
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IUpdateOrganizationReportV2Command>()
.UpdateAsync(Arg.Any<UpdateOrganizationReportV2Request>())
.Returns(expectedReport);
// Act
var result = await sutProvider.Sut.UpdateOrganizationReportAsync(orgId, reportId, request);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
Assert.IsType<OrganizationReportResponseModel>(okResult.Value);
await sutProvider.GetDependency<IUpdateOrganizationReportV2Command>()
.Received(1)
.UpdateAsync(Arg.Any<UpdateOrganizationReportV2Request>());
}
[Theory, BitAutoData]
public async Task UpdateOrganizationReportAsync_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
UpdateOrganizationReportV2RequestModel request)
{
// Arrange
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.UpdateOrganizationReportAsync(orgId, reportId, request));
await sutProvider.GetDependency<IUpdateOrganizationReportV2Command>()
.DidNotReceive()
.UpdateAsync(Arg.Any<UpdateOrganizationReportV2Request>());
}
// SummaryData Field Endpoints
[Theory, BitAutoData]
public async Task GetOrganizationReportSummaryDataByDateRangeAsync_WithValidParameters_ReturnsOkResult(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
DateTime startDate,
DateTime endDate,
List<OrganizationReportSummaryDataResponse> expectedSummaryData)
{
// Arrange
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportSummaryDataByDateRangeQuery>()
.GetOrganizationReportSummaryDataByDateRangeAsync(orgId, startDate, endDate)
.Returns(expectedSummaryData);
// Act
var result = await sutProvider.Sut.GetOrganizationReportSummaryDataByDateRangeAsync(orgId, startDate, endDate);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var responseList = Assert.IsAssignableFrom<IEnumerable<OrganizationReportSummaryDataResponseModel>>(okResult.Value);
Assert.Equal(expectedSummaryData.Count, responseList.Count());
}
[Theory, BitAutoData]
public async Task GetOrganizationReportSummaryDataByDateRangeAsync_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
DateTime startDate,
DateTime endDate)
{
// Arrange
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.GetOrganizationReportSummaryDataByDateRangeAsync(orgId, startDate, endDate));
// Verify that the query was not called
await sutProvider.GetDependency<IGetOrganizationReportSummaryDataByDateRangeQuery>()
.DidNotReceive()
.GetOrganizationReportSummaryDataByDateRangeAsync(Arg.Any<Guid>(), Arg.Any<DateTime>(), Arg.Any<DateTime>());
}
[Theory, BitAutoData]
public async Task GetOrganizationReportSummaryDataByDateRangeAsync_CallsCorrectMethods(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
DateTime startDate,
DateTime endDate,
List<OrganizationReportSummaryDataResponse> expectedSummaryData)
{
// Arrange
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportSummaryDataByDateRangeQuery>()
.GetOrganizationReportSummaryDataByDateRangeAsync(orgId, startDate, endDate)
.Returns(expectedSummaryData);
// Act
await sutProvider.Sut.GetOrganizationReportSummaryDataByDateRangeAsync(orgId, startDate, endDate);
// Assert
await sutProvider.GetDependency<ICurrentContext>()
.Received(1)
.AccessReports(orgId);
await sutProvider.GetDependency<IGetOrganizationReportSummaryDataByDateRangeQuery>()
.Received(1)
.GetOrganizationReportSummaryDataByDateRangeAsync(orgId, startDate, endDate);
}
[Theory, BitAutoData]
public async Task GetOrganizationReportSummaryAsync_WithValidIds_ReturnsOkResult(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
OrganizationReportSummaryDataResponse expectedSummaryData)
{
// Arrange
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportSummaryDataQuery>()
.GetOrganizationReportSummaryDataAsync(orgId, reportId)
.Returns(expectedSummaryData);
// Act
var result = await sutProvider.Sut.GetOrganizationReportSummaryAsync(orgId, reportId);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var response = Assert.IsType<OrganizationReportSummaryDataResponseModel>(okResult.Value);
Assert.Equal(expectedSummaryData.SummaryData, response.EncryptedData);
Assert.Equal(expectedSummaryData.ContentEncryptionKey, response.EncryptionKey);
Assert.Equal(expectedSummaryData.RevisionDate, response.Date);
}
[Theory, BitAutoData]
public async Task GetOrganizationReportSummaryAsync_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId)
{
// Arrange
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.GetOrganizationReportSummaryAsync(orgId, reportId));
// Verify that the query was not called
await sutProvider.GetDependency<IGetOrganizationReportSummaryDataQuery>()
.DidNotReceive()
.GetOrganizationReportSummaryDataAsync(Arg.Any<Guid>(), Arg.Any<Guid>());
}
[Theory, BitAutoData]
public async Task UpdateOrganizationReportSummaryAsync_WithValidRequest_ReturnsOkResult(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
UpdateOrganizationReportSummaryRequestModel request,
OrganizationReport expectedReport)
{
// Arrange
expectedReport.ReportFile = null;
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IUpdateOrganizationReportSummaryCommand>()
.UpdateOrganizationReportSummaryAsync(Arg.Any<UpdateOrganizationReportSummaryRequest>())
.Returns(expectedReport);
// Act
var result = await sutProvider.Sut.UpdateOrganizationReportSummaryAsync(orgId, reportId, request);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var expectedResponse = new OrganizationReportResponseModel(expectedReport);
Assert.Equivalent(expectedResponse, okResult.Value);
}
[Theory, BitAutoData]
public async Task UpdateOrganizationReportSummaryAsync_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
UpdateOrganizationReportSummaryRequestModel request)
{
// Arrange
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.UpdateOrganizationReportSummaryAsync(orgId, reportId, request));
// Verify that the command was not called
await sutProvider.GetDependency<IUpdateOrganizationReportSummaryCommand>()
.DidNotReceive()
.UpdateOrganizationReportSummaryAsync(Arg.Any<UpdateOrganizationReportSummaryRequest>());
}
[Theory, BitAutoData]
public async Task UpdateOrganizationReportSummaryAsync_CallsCorrectMethods(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
UpdateOrganizationReportSummaryRequestModel request,
OrganizationReport expectedReport)
{
// Arrange
expectedReport.ReportFile = null;
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IUpdateOrganizationReportSummaryCommand>()
.UpdateOrganizationReportSummaryAsync(Arg.Any<UpdateOrganizationReportSummaryRequest>())
.Returns(expectedReport);
// Act
await sutProvider.Sut.UpdateOrganizationReportSummaryAsync(orgId, reportId, request);
// Assert
await sutProvider.GetDependency<ICurrentContext>()
.Received(1)
.AccessReports(orgId);
await sutProvider.GetDependency<IUpdateOrganizationReportSummaryCommand>()
.Received(1)
.UpdateOrganizationReportSummaryAsync(Arg.Any<UpdateOrganizationReportSummaryRequest>());
}
// ApplicationData Field Endpoints
[Theory, BitAutoData]
public async Task GetOrganizationReportApplicationDataAsync_WithValidIds_ReturnsOkResult(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
OrganizationReportApplicationDataResponse expectedApplicationData)
{
// Arrange
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportApplicationDataQuery>()
.GetOrganizationReportApplicationDataAsync(orgId, reportId)
.Returns(expectedApplicationData);
// Act
var result = await sutProvider.Sut.GetOrganizationReportApplicationDataAsync(orgId, reportId);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var response = Assert.IsType<OrganizationReportApplicationDataResponseModel>(okResult.Value);
Assert.Equal(expectedApplicationData.ApplicationData, response.ApplicationData);
}
[Theory, BitAutoData]
public async Task GetOrganizationReportApplicationDataAsync_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId)
{
// Arrange
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.GetOrganizationReportApplicationDataAsync(orgId, reportId));
// Verify that the query was not called
await sutProvider.GetDependency<IGetOrganizationReportApplicationDataQuery>()
.DidNotReceive()
.GetOrganizationReportApplicationDataAsync(Arg.Any<Guid>(), Arg.Any<Guid>());
}
[Theory, BitAutoData]
public async Task GetOrganizationReportApplicationDataAsync_WhenApplicationDataNotFound_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId)
{
// Arrange
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportApplicationDataQuery>()
.GetOrganizationReportApplicationDataAsync(orgId, reportId)
.Returns((OrganizationReportApplicationDataResponse)null);
// Act & Assert
var exception = await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.GetOrganizationReportApplicationDataAsync(orgId, reportId));
Assert.Equal("Organization report application data not found.", exception.Message);
}
[Theory, BitAutoData]
public async Task GetOrganizationReportApplicationDataAsync_CallsCorrectMethods(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
OrganizationReportApplicationDataResponse expectedApplicationData)
{
// Arrange
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportApplicationDataQuery>()
.GetOrganizationReportApplicationDataAsync(orgId, reportId)
.Returns(expectedApplicationData);
// Act
await sutProvider.Sut.GetOrganizationReportApplicationDataAsync(orgId, reportId);
// Assert
await sutProvider.GetDependency<ICurrentContext>()
.Received(1)
.AccessReports(orgId);
await sutProvider.GetDependency<IGetOrganizationReportApplicationDataQuery>()
.Received(1)
.GetOrganizationReportApplicationDataAsync(orgId, reportId);
}
[Theory, BitAutoData]
public async Task UpdateOrganizationReportApplicationDataAsync_WithValidRequest_ReturnsOkResult(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
UpdateOrganizationReportApplicationDataRequestModel request,
OrganizationReport expectedReport)
{
// Arrange
expectedReport.ReportFile = null;
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IUpdateOrganizationReportApplicationDataCommand>()
.UpdateOrganizationReportApplicationDataAsync(Arg.Any<UpdateOrganizationReportApplicationDataRequest>())
.Returns(expectedReport);
// Act
var result = await sutProvider.Sut.UpdateOrganizationReportApplicationDataAsync(orgId, reportId, request);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var expectedResponse = new OrganizationReportResponseModel(expectedReport);
Assert.Equivalent(expectedResponse, okResult.Value);
}
[Theory, BitAutoData]
public async Task UpdateOrganizationReportApplicationDataAsync_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
UpdateOrganizationReportApplicationDataRequestModel request)
{
// Arrange
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.UpdateOrganizationReportApplicationDataAsync(orgId, reportId, request));
// Verify that the command was not called
await sutProvider.GetDependency<IUpdateOrganizationReportApplicationDataCommand>()
.DidNotReceive()
.UpdateOrganizationReportApplicationDataAsync(Arg.Any<UpdateOrganizationReportApplicationDataRequest>());
}
[Theory, BitAutoData]
public async Task UpdateOrganizationReportApplicationDataAsync_CallsCorrectMethods(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId,
UpdateOrganizationReportApplicationDataRequestModel request,
OrganizationReport expectedReport)
{
// Arrange
expectedReport.ReportFile = null;
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IUpdateOrganizationReportApplicationDataCommand>()
.UpdateOrganizationReportApplicationDataAsync(Arg.Any<UpdateOrganizationReportApplicationDataRequest>())
.Returns(expectedReport);
// Act
await sutProvider.Sut.UpdateOrganizationReportApplicationDataAsync(orgId, reportId, request);
// Assert
await sutProvider.GetDependency<ICurrentContext>()
.Received(1)
.AccessReports(orgId);
await sutProvider.GetDependency<IUpdateOrganizationReportApplicationDataCommand>()
.Received(1)
.UpdateOrganizationReportApplicationDataAsync(Arg.Any<UpdateOrganizationReportApplicationDataRequest>());
}
// DownloadReportFileAsync
[Theory, BitAutoData]
public async Task DownloadReportFileAsync_WithValidFile_ReturnsFileStream(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
var reportFile = new ReportFile { Id = "file-id", FileName = "report.json", Size = 1024, Validated = true };
report.OrganizationId = orgId;
report.SetReportFile(reportFile);
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
var stream = new MemoryStream(new byte[] { 1, 2, 3 });
sutProvider.GetDependency<IOrganizationReportStorageService>()
.GetReportReadStreamAsync(report, Arg.Any<ReportFile>())
.Returns(stream);
// Act
var result = await sutProvider.Sut.DownloadReportFileAsync(orgId, report.Id);
// Assert
var fileResult = Assert.IsType<FileStreamResult>(result);
Assert.Equal("application/octet-stream", fileResult.ContentType);
Assert.Equal("report.json", fileResult.FileDownloadName);
}
[Theory, BitAutoData]
public async Task DownloadReportFileAsync_WithNoFileData_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
report.OrganizationId = orgId;
report.ReportFile = null;
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.DownloadReportFileAsync(orgId, report.Id));
await sutProvider.GetDependency<IOrganizationReportStorageService>()
.DidNotReceive()
.GetReportReadStreamAsync(Arg.Any<OrganizationReport>(), Arg.Any<ReportFile>());
}
[Theory, BitAutoData]
public async Task DownloadReportFileAsync_WithNullStream_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
var reportFile = new ReportFile { Id = "file-id", FileName = "report.json", Size = 1024, Validated = true };
report.OrganizationId = orgId;
report.SetReportFile(reportFile);
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
sutProvider.GetDependency<IOrganizationReportStorageService>()
.GetReportReadStreamAsync(report, Arg.Any<ReportFile>())
.Returns((Stream)null);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.DownloadReportFileAsync(orgId, report.Id));
}
[Theory, BitAutoData]
public async Task DownloadReportFileAsync_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId)
{
// Arrange
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.DownloadReportFileAsync(orgId, reportId));
await sutProvider.GetDependency<IOrganizationReportStorageService>()
.DidNotReceive()
.GetReportReadStreamAsync(Arg.Any<OrganizationReport>(), Arg.Any<ReportFile>());
}
[Theory, BitAutoData]
public async Task DownloadReportFileAsync_OrgMismatch_ThrowsBadRequestException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
report.OrganizationId = Guid.NewGuid();
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.DownloadReportFileAsync(orgId, report.Id));
Assert.Equal("Invalid report ID", exception.Message);
}
// UploadReportFileAsync
[Theory, BitAutoData]
public async Task UploadReportFileAsync_WithoutAccess_ThrowsNotFoundException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
Guid reportId)
{
// Arrange
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(false);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.UploadReportFileAsync(orgId, reportId, "file-id"));
}
[Theory, BitAutoData]
public async Task UploadReportFileAsync_OrgMismatch_ThrowsBadRequestException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange
report.OrganizationId = Guid.NewGuid();
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.UploadReportFileAsync(orgId, report.Id, "file-id"));
Assert.Equal("Invalid report ID", exception.Message);
}
[Theory, BitAutoData]
public async Task UploadReportFileAsync_InvalidContentType_ThrowsBadRequestException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
OrganizationReport report)
{
// Arrange — Request is null in SutProvider context, so ContentType check rejects
report.OrganizationId = orgId;
SetupAuthorization(sutProvider, orgId);
sutProvider.GetDependency<IGetOrganizationReportQuery>()
.GetOrganizationReportAsync(report.Id)
.Returns(report);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.UploadReportFileAsync(orgId, report.Id, "file-id"));
Assert.Equal("Invalid content.", exception.Message);
}
// CreateOrganizationReportAsync - V2 file size cap
[Theory, BitAutoData]
public async Task CreateOrganizationReportAsync_V2_FileSizeExceedsLimit_ThrowsBadRequestException(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId,
AddOrganizationReportRequestModel request)
{
// Arrange
request.FileSize = Constants.FileSize501mb + 1;
SetupV2Authorization(sutProvider, orgId);
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.CreateOrganizationReportAsync(orgId, request));
Assert.Equal("Max file size is 500 MB.", exception.Message);
await sutProvider.GetDependency<ICreateOrganizationReportCommand>()
.DidNotReceive()
.CreateAsync(Arg.Any<AddOrganizationReportRequest>());
}
// Helper methods for authorization mocks
private static void SetupAuthorization(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId)
{
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(true);
// TODO: Re-enable in PM-37469 when UseRiskInsights access control is restored
// sutProvider.GetDependency<IApplicationCacheService>()
// .GetOrganizationAbilityAsync(orgId)
// .Returns(new OrganizationAbility { UseRiskInsights = true });
}
private static void SetupV2Authorization(
SutProvider<OrganizationReportsController> sutProvider,
Guid orgId)
{
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AccessIntelligenceVersion2)
.Returns(true);
sutProvider.GetDependency<ICurrentContext>()
.AccessReports(orgId)
.Returns(true);
// TODO: Re-enable in PM-37469 when UseRiskInsights access control is restored
// sutProvider.GetDependency<IApplicationCacheService>()
// .GetOrganizationAbilityAsync(orgId)
// .Returns(new OrganizationAbility { UseRiskInsights = true });
}
}