Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create default storagePolicy on setup #904

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
15 changes: 9 additions & 6 deletions src/protagonist/API.Tests/Integration/ApplicationTests.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using API.Client;
using API.Tests.Integration.Infrastructure;
using DLCS.HydraModel;
using DLCS.Repository;
using Microsoft.EntityFrameworkCore;
Expand All @@ -11,17 +9,17 @@
namespace API.Tests.Integration;

[Trait("Category", "Integration")]
[Collection(CollectionDefinitions.DatabaseCollection.CollectionName)]
public class ApplicationTests : IClassFixture<ProtagonistAppFactory<Startup>>
{
private readonly HttpClient httpClient;
private readonly DlcsContext dlcsContext;

public ApplicationTests(DlcsDatabaseFixture dbFixture, ProtagonistAppFactory<Startup> factory)
public ApplicationTests(ProtagonistAppFactory<Startup> factory)
{
var dbFixture = new DlcsDefaultDatabaseFixture();
dbFixture.InitializeAsync().Wait();
dlcsContext = dbFixture.DbContext;
httpClient = factory.WithConnectionString(dbFixture.ConnectionString).CreateClient();
dbFixture.CleanUp();
}

[Fact]
Expand All @@ -39,7 +37,7 @@ public async Task SetupApplication_Fail_Customer1AlreadyExists()
}

[Fact]
public async Task SetupApplication_Success_CreatesCustomerAndCounter()
public async Task SetupApplication_Success_CreatesCustomerCounterAndStoragePolicy()
{
// Act
var response = await httpClient.PostAsync("/setup", null!);
Expand All @@ -53,5 +51,10 @@ public async Task SetupApplication_Success_CreatesCustomerAndCounter()
(await dlcsContext.EntityCounters
.AnyAsync(c => c.Scope == "1" && c.Customer == 1 && c.Type == "space"))
.Should().BeTrue();

// Note: -99 value comes from appsttings.Testing.json
var storagePolicy = await dlcsContext.StoragePolicies.SingleAsync(s => s.Id == "default");
storagePolicy.MaximumNumberOfStoredImages.Should().Be(-99);
storagePolicy.MaximumTotalSizeOfStoredImages.Should().Be(-99);
}
}
4 changes: 3 additions & 1 deletion src/protagonist/API.Tests/appsettings.Testing.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
"DLCS": {
"ApiRoot": "https://api.dlcs.digirati.io",
"ResourceRoot": "https://dlcs.digirati.io",
"EngineRoot": "http://engine.dlcs.digirati.io"
"EngineRoot": "http://engine.dlcs.digirati.io",
"DefaultPolicyMaxNumber": -99,
"DefaultPolicyMaxSize": -99
},
"PageSize": 100,
"ApiSalt": "this-is-a-salt",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using API.Auth;
using API.Features.Customer.Requests;
using API.Settings;
using DLCS.Core.Settings;
using DLCS.Model;
using DLCS.Model.Storage;
using DLCS.Repository;
using DLCS.Repository.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;

namespace API.Features.Application.Requests;

Expand All @@ -20,13 +24,15 @@ public class SetupApplicationHandler : IRequestHandler<SetupApplication, CreateA
private readonly DlcsContext dbContext;
private readonly ApiKeyGenerator apiKeyGenerator;
private readonly IEntityCounterRepository entityCounterRepository;
private readonly DlcsSettings dlcsSettings;

public SetupApplicationHandler(DlcsContext dbContext, ApiKeyGenerator apiKeyGenerator,
IEntityCounterRepository entityCounterRepository)
IEntityCounterRepository entityCounterRepository, IOptions<ApiSettings> apiOptions)
{
this.dbContext = dbContext;
this.apiKeyGenerator = apiKeyGenerator;
this.entityCounterRepository = entityCounterRepository;
dlcsSettings = apiOptions.Value.DLCS;
}

public async Task<CreateApiKeyResult> Handle(SetupApplication request, CancellationToken cancellationToken)
Expand All @@ -48,14 +54,26 @@ public async Task<CreateApiKeyResult> Handle(SetupApplication request, Cancellat
};
var (apiKey, apiSecret) = apiKeyGenerator.CreateApiKey(adminCustomer);
adminCustomer.Keys = new[] { apiKey };

await dbContext.Customers.AddAsync(adminCustomer, cancellationToken);

await CreateDefaultStoragePolicy(cancellationToken);
var updateCount = await dbContext.SaveChangesAsync(cancellationToken);

await entityCounterRepository.Create(adminCustomer.Id, KnownEntityCounters.CustomerSpaces, adminCustomer.Id.ToString());

return updateCount == 1
return updateCount == 2
? CreateApiKeyResult.Success(apiKey, apiSecret)
: CreateApiKeyResult.Fail("Error creating customer");
}

private async Task CreateDefaultStoragePolicy(CancellationToken cancellationToken)
{
var storagePolicy = new StoragePolicy
{
Id = StoragePolicy.DefaultStoragePolicyName,
MaximumNumberOfStoredImages = dlcsSettings.DefaultPolicyMaxNumber,
MaximumTotalSizeOfStoredImages = dlcsSettings.DefaultPolicyMaxSize,
};
await dbContext.StoragePolicies.AddAsync(storagePolicy, cancellationToken);
}
}
14 changes: 13 additions & 1 deletion src/protagonist/DLCS.Core/Settings/DlcsSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@
/// <summary>
/// The base URI of DLCS to hand-off requests to.
/// </summary>
public Uri ApiRoot { get; set; }

Check warning on line 14 in src/protagonist/DLCS.Core/Settings/DlcsSettings.cs

View workflow job for this annotation

GitHub Actions / test-dotnet

Non-nullable property 'ApiRoot' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

/// <summary>
/// The base URI for image services and other public-facing resources
/// </summary>
public Uri ResourceRoot { get; set; }

Check warning on line 19 in src/protagonist/DLCS.Core/Settings/DlcsSettings.cs

View workflow job for this annotation

GitHub Actions / test-dotnet

Non-nullable property 'ResourceRoot' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

/// <summary>
/// The base URI for the engine
/// </summary>
public Uri EngineRoot { get; set; }

Check warning on line 24 in src/protagonist/DLCS.Core/Settings/DlcsSettings.cs

View workflow job for this annotation

GitHub Actions / test-dotnet

Non-nullable property 'EngineRoot' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

/// <summary>
/// Default timeout for dlcs api requests.
Expand All @@ -31,12 +31,12 @@
/// <summary>
/// URL format of NamedQuery for generating manifest for space.
/// </summary>
public string SpaceManifestQuery { get; set; }

Check warning on line 34 in src/protagonist/DLCS.Core/Settings/DlcsSettings.cs

View workflow job for this annotation

GitHub Actions / test-dotnet

Non-nullable property 'SpaceManifestQuery' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

/// <summary>
/// URL format for generating manifests for single assets
/// </summary>
public string SingleAssetManifestTemplate { get; set; }

Check warning on line 39 in src/protagonist/DLCS.Core/Settings/DlcsSettings.cs

View workflow job for this annotation

GitHub Actions / test-dotnet

Non-nullable property 'SingleAssetManifestTemplate' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

/// <summary>
/// 256bit or longer, Base64 encoded, JWT secret
Expand All @@ -47,4 +47,16 @@
/// List of valid issuers of JWT for authentication
/// </summary>
public string[] JwtValidIssuers { get; set; } = Array.Empty<string>();
}

/// <summary>
/// Max number of stored items for "default" storage policy
/// </summary>
/// <remarks>These are used during 1 off setup only</remarks>
public long DefaultPolicyMaxNumber { get; set; } = 1000000000;

/// <summary>
/// Max number of stored bytes for "default" storage policy
/// </summary>
/// <remarks>These are used during 1 off setup only</remarks>
public long DefaultPolicyMaxSize { get; set; } = 1000000000000000;
}
4 changes: 3 additions & 1 deletion src/protagonist/DLCS.Model/Storage/StoragePolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
namespace DLCS.Model.Storage;

[DebuggerDisplay("{Id}")]
public partial class StoragePolicy
public class StoragePolicy
{
public string Id { get; set; }
public long MaximumNumberOfStoredImages { get; set; }
public long MaximumTotalSizeOfStoredImages { get; set; }

public const string DefaultStoragePolicyName = "default";
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ await dlcsContext.CustomerStorages.SingleOrDefaultAsync(cs =>

if (spaceId == 0)
{
storageForSpace.StoragePolicy = "default"; // this isn't set on Customer
storageForSpace.StoragePolicy = StoragePolicy.DefaultStoragePolicyName; // this isn't set on Customer
// This space0 row isn't created when a customer is created, either - but should it?
}

Expand Down
50 changes: 28 additions & 22 deletions src/protagonist/Test.Helpers/Integration/DlcsDatabaseFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Threading.Tasks;
using DLCS.Model.Auth.Entities;
using DLCS.Model.Customers;
using DLCS.Model.DeliveryChannels;
using DLCS.Model.Policies;
using DLCS.Model.Spaces;
using DLCS.Model.Storage;
Expand All @@ -20,27 +19,9 @@ namespace Test.Helpers.Integration;
/// Xunit fixture that manages lifecycle for Postgres 12 container with basic migration applied.
/// Seeds Customer 99 with 1 space and default thumbnailPolicy
/// </summary>
public class DlcsDatabaseFixture : IAsyncLifetime
public class DlcsDatabaseFixture : DlcsDefaultDatabaseFixture
{
private readonly PostgreSqlTestcontainer postgresContainer;

public DlcsContext DbContext { get; private set; }
public string ConnectionString { get; private set; }

public DlcsDatabaseFixture()
{
var postgresBuilder = new TestcontainersBuilder<PostgreSqlTestcontainer>()
.WithDatabase(new PostgreSqlTestcontainerConfiguration("postgres:13-alpine")
{
Database = "db",
Password = "postgres_pword",
Username = "postgres"
})
.WithCleanUp(true)
.WithLabel("protagonist_test", "True");

postgresContainer = postgresBuilder.Build();
}
protected override Task InitialiseDb() => SeedCustomer();

/// <summary>
/// Delete any standing data - leaves data set in Seed method
Expand Down Expand Up @@ -189,6 +170,31 @@ await DbContext.Roles.AddAsync(new Role

await DbContext.SaveChangesAsync();
}
}

public class DlcsDefaultDatabaseFixture : IAsyncLifetime
{
private readonly PostgreSqlTestcontainer postgresContainer;

public DlcsContext DbContext { get; private set; }
public string ConnectionString { get; private set; }

public DlcsDefaultDatabaseFixture()
{
var postgresBuilder = new TestcontainersBuilder<PostgreSqlTestcontainer>()
.WithDatabase(new PostgreSqlTestcontainerConfiguration("postgres:13-alpine")
{
Database = "db",
Password = "postgres_pword",
Username = "postgres"
})
.WithCleanUp(true)
.WithLabel("protagonist_test", "True");

postgresContainer = postgresBuilder.Build();
}

protected virtual Task InitialiseDb() => Task.CompletedTask;

public async Task InitializeAsync()
{
Expand All @@ -198,7 +204,7 @@ public async Task InitializeAsync()
await postgresContainer.StartAsync();
SetPropertiesFromContainer();
await DbContext.Database.MigrateAsync();
await SeedCustomer();
await InitialiseDb();
}
catch (Exception ex)
{
Expand Down
Loading