mirror of
https://github.com/bitwarden/server.git
synced 2025-04-21 04:55:08 -05:00
Customizer
This commit is contained in:
parent
d5f118c633
commit
691afc3597
@ -1,16 +1,6 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Bit.Core.Enums;
|
|
||||||
using Bit.Core.Settings;
|
|
||||||
using Bit.Infrastructure.Dapper;
|
|
||||||
using Bit.Infrastructure.EntityFramework;
|
|
||||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
|
||||||
using Bit.Infrastructure.IntegrationTest.Services;
|
|
||||||
using Bit.Infrastructure.IntegrationTest.Utilities;
|
using Bit.Infrastructure.IntegrationTest.Utilities;
|
||||||
using Microsoft.Extensions.Caching.Distributed;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Time.Testing;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Sdk;
|
using Xunit.Sdk;
|
||||||
using Xunit.v3;
|
using Xunit.v3;
|
||||||
@ -19,29 +9,72 @@ namespace Bit.Infrastructure.IntegrationTest;
|
|||||||
|
|
||||||
public class DatabaseDataAttribute : DataAttribute
|
public class DatabaseDataAttribute : DataAttribute
|
||||||
{
|
{
|
||||||
public bool SelfHosted { get; set; }
|
|
||||||
public bool UseFakeTimeProvider { get; set; }
|
public bool UseFakeTimeProvider { get; set; }
|
||||||
public string? MigrationName { get; set; }
|
|
||||||
|
|
||||||
public override ValueTask<IReadOnlyCollection<ITheoryDataRow>> GetData(MethodInfo testMethod, DisposalTracker disposalTracker)
|
public override async ValueTask<IReadOnlyCollection<ITheoryDataRow>> GetData(MethodInfo testMethod, DisposalTracker disposalTracker)
|
||||||
{
|
{
|
||||||
var builders = DatabaseStartup.Builders;
|
var customizers = GetOrderedCustomizers(testMethod);
|
||||||
|
|
||||||
if (builders == null)
|
var databases = DatabaseStartup.Databases;
|
||||||
|
|
||||||
|
if (databases == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Builders wasn't supplied, this likely means DatabaseStartup didn't run.");
|
throw new InvalidOperationException("Databases wasn't supplied, this likely means DatabaseStartup didn't run.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var theoryData = new ITheoryDataRow[builders.Count];
|
var theories = new ITheoryDataRow[databases.Count];
|
||||||
for (var i = 0; i < builders.Count; i++)
|
|
||||||
|
for (var i = 0; i < theories.Length; i++)
|
||||||
{
|
{
|
||||||
theoryData[i] = builders[i](testMethod, disposalTracker, this);
|
var customizationContext = new CustomizationContext(databases[i] with {}, testMethod, disposalTracker);
|
||||||
|
foreach (var customizer in customizers)
|
||||||
|
{
|
||||||
|
await customizer.CustomizeAsync(customizationContext);
|
||||||
}
|
}
|
||||||
return new(theoryData);
|
|
||||||
|
var isEnabled = customizationContext.Enabled ?? customizationContext.Database.Enabled;
|
||||||
|
|
||||||
|
TheoryDataRowBase theory;
|
||||||
|
|
||||||
|
if (!isEnabled)
|
||||||
|
{
|
||||||
|
theory = new TheoryDataRow()
|
||||||
|
.WithSkip("Not Enabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
theory = new ServiceTheoryDataRow(testMethod, disposalTracker, customizationContext.Services.BuildServiceProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
theory
|
||||||
|
.WithTrait("Type", customizationContext.Database.Type.ToString())
|
||||||
|
.WithTrait("ConnectionString", customizationContext.Database.ConnectionString ?? "(none)")
|
||||||
|
.WithTestDisplayName($"{testMethod.Name}[{customizationContext.Database.Name ?? customizationContext.Database.Type.ToString()}]");
|
||||||
|
|
||||||
|
theories[i] = theory;
|
||||||
|
}
|
||||||
|
|
||||||
|
return theories;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool SupportsDiscoveryEnumeration()
|
public override bool SupportsDiscoveryEnumeration()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<TestCustomizerAttribute> GetOrderedCustomizers(MethodInfo methodInfo)
|
||||||
|
{
|
||||||
|
var assemblyAttributes = methodInfo.DeclaringType?.Assembly.GetCustomAttributes<TestCustomizerAttribute>() ?? [];
|
||||||
|
var typeAttributes = methodInfo.DeclaringType?.GetCustomAttributes<TestCustomizerAttribute>() ?? [];
|
||||||
|
var methodAttributes = methodInfo.GetCustomAttributes<TestCustomizerAttribute>();
|
||||||
|
|
||||||
|
IReadOnlyCollection<TestCustomizerAttribute> allAttributes = [..assemblyAttributes, ..typeAttributes, ..methodAttributes];
|
||||||
|
|
||||||
|
if (allAttributes.Count == 0)
|
||||||
|
{
|
||||||
|
return [DefaultCustomizerAttribute.Instance];
|
||||||
|
}
|
||||||
|
|
||||||
|
return allAttributes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using Bit.Infrastructure.IntegrationTest.Services;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Bit.Infrastructure.IntegrationTest.Utilities;
|
||||||
|
|
||||||
|
public class AutoMigrateAttribute : TestCustomizerAttribute
|
||||||
|
{
|
||||||
|
public AutoMigrateAttribute(string? migrationName = null)
|
||||||
|
{
|
||||||
|
MigrationName = migrationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? MigrationName { get; }
|
||||||
|
|
||||||
|
public override Task CustomizeAsync(CustomizationContext customizationContext)
|
||||||
|
{
|
||||||
|
// Add migration services
|
||||||
|
var database = customizationContext.Database;
|
||||||
|
|
||||||
|
if (database.Type == SupportedDatabaseProviders.SqlServer && !database.UseEf)
|
||||||
|
{
|
||||||
|
// Add migrator service
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Add migrator service
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build services provider early and run migrations
|
||||||
|
var sp = customizationContext.Services.BuildServiceProvider();
|
||||||
|
var migrator = sp.GetRequiredService<IMigrationTesterService>();
|
||||||
|
migrator.ApplyMigration()
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +1,15 @@
|
|||||||
using System.Reflection;
|
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Settings;
|
|
||||||
using Bit.Infrastructure.Dapper;
|
|
||||||
using Bit.Infrastructure.EntityFramework;
|
|
||||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
|
||||||
using Bit.Infrastructure.IntegrationTest.Services;
|
|
||||||
using Microsoft.Extensions.Caching.Distributed;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Time.Testing;
|
|
||||||
using Xunit;
|
|
||||||
using Xunit.v3;
|
using Xunit.v3;
|
||||||
using Xunit.Sdk;
|
using Xunit.Sdk;
|
||||||
|
|
||||||
namespace Bit.Infrastructure.IntegrationTest.Utilities;
|
namespace Bit.Infrastructure.IntegrationTest.Utilities;
|
||||||
|
|
||||||
using TheoryDataBuilder = Func<MethodInfo, DisposalTracker, DatabaseDataAttribute, ITheoryDataRow>;
|
public record Database
|
||||||
|
|
||||||
public class Database
|
|
||||||
{
|
{
|
||||||
|
public string? Name { get; set; }
|
||||||
public SupportedDatabaseProviders Type { get; set; }
|
public SupportedDatabaseProviders Type { get; set; }
|
||||||
public string ConnectionString { get; set; } = default!;
|
public string? ConnectionString { get; set; }
|
||||||
public bool UseEf { get; set; }
|
public bool UseEf { get; set; }
|
||||||
public bool Enabled { get; set; } = true;
|
public bool Enabled { get; set; } = true;
|
||||||
}
|
}
|
||||||
@ -33,16 +21,36 @@ internal class TypedConfig
|
|||||||
|
|
||||||
public class DatabaseStartup : ITestPipelineStartup
|
public class DatabaseStartup : ITestPipelineStartup
|
||||||
{
|
{
|
||||||
public static IReadOnlyList<TheoryDataBuilder>? Builders { get; private set; }
|
public static IReadOnlyList<Database>? Databases { get; private set; }
|
||||||
|
|
||||||
public ValueTask StartAsync(IMessageSink diagnosticMessageSink)
|
public ValueTask StartAsync(IMessageSink diagnosticMessageSink)
|
||||||
{
|
{
|
||||||
HashSet<SupportedDatabaseProviders> unconfiguredDatabases =
|
List<Database> unconfiguredDatabases =
|
||||||
[
|
[
|
||||||
SupportedDatabaseProviders.SqlServer,
|
new Database
|
||||||
SupportedDatabaseProviders.MySql,
|
{
|
||||||
SupportedDatabaseProviders.Postgres,
|
Type = SupportedDatabaseProviders.SqlServer,
|
||||||
SupportedDatabaseProviders.Sqlite
|
Enabled = false,
|
||||||
|
Name = "Unconfigured",
|
||||||
|
},
|
||||||
|
new Database
|
||||||
|
{
|
||||||
|
Type = SupportedDatabaseProviders.MySql,
|
||||||
|
Enabled = false,
|
||||||
|
Name = "Unconfigured",
|
||||||
|
},
|
||||||
|
new Database
|
||||||
|
{
|
||||||
|
Type = SupportedDatabaseProviders.Postgres,
|
||||||
|
Enabled = false,
|
||||||
|
Name = "Unconfigured",
|
||||||
|
},
|
||||||
|
new Database
|
||||||
|
{
|
||||||
|
Type = SupportedDatabaseProviders.Sqlite,
|
||||||
|
Enabled = false,
|
||||||
|
Name = "Unconfigured",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Do startup things
|
// Do startup things
|
||||||
@ -54,57 +62,24 @@ public class DatabaseStartup : ITestPipelineStartup
|
|||||||
|
|
||||||
var typedConfig = configuration.Get<TypedConfig>();
|
var typedConfig = configuration.Get<TypedConfig>();
|
||||||
|
|
||||||
var theories = new List<TheoryDataBuilder>();
|
|
||||||
|
|
||||||
if (typedConfig is not { Databases: var databases })
|
if (typedConfig is not { Databases: var databases })
|
||||||
{
|
{
|
||||||
foreach (var unconfiguredDatabase in unconfiguredDatabases)
|
Databases = unconfiguredDatabases;
|
||||||
{
|
|
||||||
theories.Add((mi, _, _) => new TheoryDataRow()
|
|
||||||
.WithSkip("Unconfigured")
|
|
||||||
.WithTestDisplayName(TestName(mi, unconfiguredDatabase))
|
|
||||||
.WithTrait("Type", unconfiguredDatabase.ToString()));
|
|
||||||
}
|
|
||||||
return ValueTask.CompletedTask;
|
return ValueTask.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var allDatabases = new List<Database>();
|
||||||
foreach (var database in databases)
|
foreach (var database in databases)
|
||||||
{
|
{
|
||||||
unconfiguredDatabases.Remove(database.Type);
|
unconfiguredDatabases.RemoveAll(db => db.Type == database.Type);
|
||||||
if (!database.Enabled)
|
allDatabases.Add(database);
|
||||||
{
|
|
||||||
theories.Add((mi, _, _) => new TheoryDataRow()
|
|
||||||
.WithSkip($"Disabled")
|
|
||||||
.WithTestDisplayName(TestName(mi, database.Type))
|
|
||||||
.WithTrait("Type", database.Type.ToString())
|
|
||||||
.WithTrait("ConnectionString", database.ConnectionString));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Build service provider for database
|
|
||||||
theories.Add((methodInfo, disposalTracker, databaseDataAttribute) =>
|
|
||||||
{
|
|
||||||
var sp = BuildServiceProvider(databaseDataAttribute, database);
|
|
||||||
|
|
||||||
return new ServiceTheoryDataRow(methodInfo, disposalTracker, sp)
|
|
||||||
.WithTestDisplayName(TestName(methodInfo, database.Type))
|
|
||||||
.WithTrait("Type", database.Type.ToString())
|
|
||||||
.WithTrait("ConnectionString", database.ConnectionString);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add entry for all still unconfigured database types
|
// Add entry for all still unconfigured database types
|
||||||
foreach (var unconfiguredDatabase in unconfiguredDatabases)
|
allDatabases.AddRange(unconfiguredDatabases);
|
||||||
{
|
|
||||||
theories.Add((mi, _, _) => new TheoryDataRow()
|
|
||||||
.WithSkip("Not Configured")
|
|
||||||
.WithTestDisplayName(TestName(mi, unconfiguredDatabase))
|
|
||||||
.WithTrait("Type", unconfiguredDatabase.ToString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Builders = theories;
|
Databases = allDatabases;
|
||||||
|
|
||||||
return ValueTask.CompletedTask;
|
return ValueTask.CompletedTask;
|
||||||
}
|
}
|
||||||
@ -113,73 +88,4 @@ public class DatabaseStartup : ITestPipelineStartup
|
|||||||
{
|
{
|
||||||
return ValueTask.CompletedTask;
|
return ValueTask.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string TestName(MethodInfo methodInfo, SupportedDatabaseProviders database)
|
|
||||||
{
|
|
||||||
// Add containing type name to the beginning?
|
|
||||||
return $"{methodInfo.Name}({database})";
|
|
||||||
}
|
|
||||||
|
|
||||||
private IServiceProvider BuildServiceProvider(DatabaseDataAttribute databaseData, Database database)
|
|
||||||
{
|
|
||||||
var services = new ServiceCollection();
|
|
||||||
services.AddLogging(builder =>
|
|
||||||
{
|
|
||||||
builder.AddProvider(new XunitLoggerProvider(LogLevel.Information));
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddDataProtection();
|
|
||||||
|
|
||||||
if (databaseData.UseFakeTimeProvider)
|
|
||||||
{
|
|
||||||
services.AddSingleton<TimeProvider, FakeTimeProvider>();
|
|
||||||
}
|
|
||||||
|
|
||||||
services.AddSingleton(database);
|
|
||||||
|
|
||||||
if (database.Type == SupportedDatabaseProviders.SqlServer && !database.UseEf)
|
|
||||||
{
|
|
||||||
services.AddDapperRepositories(databaseData.SelfHosted);
|
|
||||||
var globalSettings = new GlobalSettings
|
|
||||||
{
|
|
||||||
DatabaseProvider = "sqlServer",
|
|
||||||
SqlServer = new GlobalSettings.SqlSettings
|
|
||||||
{
|
|
||||||
ConnectionString = database.ConnectionString,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
services.AddSingleton(globalSettings);
|
|
||||||
services.AddSingleton<IGlobalSettings>(globalSettings);
|
|
||||||
services.AddDistributedSqlServerCache((options) =>
|
|
||||||
{
|
|
||||||
options.ConnectionString = database.ConnectionString;
|
|
||||||
options.SchemaName = "dbo";
|
|
||||||
options.TableName = "Cache";
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(databaseData.MigrationName))
|
|
||||||
{
|
|
||||||
services.AddSingleton<IMigrationTesterService, SqlMigrationTesterService>(
|
|
||||||
sp => new SqlMigrationTesterService(database.ConnectionString, databaseData.MigrationName)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
services.SetupEntityFramework(database.ConnectionString, database.Type);
|
|
||||||
services.AddPasswordManagerEFRepositories(databaseData.SelfHosted);
|
|
||||||
services.AddSingleton<IDistributedCache, EntityFrameworkCache>();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(databaseData.MigrationName))
|
|
||||||
{
|
|
||||||
services.AddSingleton<IMigrationTesterService, EfMigrationTesterService>(sp =>
|
|
||||||
{
|
|
||||||
var dbContext = sp.GetRequiredService<DatabaseContext>();
|
|
||||||
return new EfMigrationTesterService(dbContext, database.Type, databaseData.MigrationName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return services.BuildServiceProvider();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
using Bit.Core.Enums;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
using Microsoft.Data.Sqlite;
|
||||||
|
using MySqlConnector;
|
||||||
|
using Npgsql;
|
||||||
|
|
||||||
|
namespace Bit.Infrastructure.IntegrationTest.Utilities;
|
||||||
|
|
||||||
|
public class DbSiloAttribute : TestCustomizerAttribute
|
||||||
|
{
|
||||||
|
public string DatabaseName { get; }
|
||||||
|
|
||||||
|
public DbSiloAttribute(string databaseName)
|
||||||
|
{
|
||||||
|
DatabaseName = databaseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task CustomizeAsync(CustomizationContext customizationContext)
|
||||||
|
{
|
||||||
|
var database = customizationContext.Database;
|
||||||
|
if (!database.Enabled || string.IsNullOrEmpty(database.ConnectionString))
|
||||||
|
{
|
||||||
|
// Nothing to customize
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (database.Type == SupportedDatabaseProviders.MySql)
|
||||||
|
{
|
||||||
|
var connectionStringBuilder = new MySqlConnectionStringBuilder(database.ConnectionString)
|
||||||
|
{
|
||||||
|
Database = DatabaseName
|
||||||
|
};
|
||||||
|
|
||||||
|
database.ConnectionString = connectionStringBuilder.ConnectionString;
|
||||||
|
}
|
||||||
|
else if(database.Type == SupportedDatabaseProviders.Postgres)
|
||||||
|
{
|
||||||
|
var connectionStringBuilder = new NpgsqlConnectionStringBuilder(database.ConnectionString)
|
||||||
|
{
|
||||||
|
Database = DatabaseName
|
||||||
|
};
|
||||||
|
|
||||||
|
database.ConnectionString = connectionStringBuilder.ConnectionString;
|
||||||
|
}
|
||||||
|
else if (database.Type == SupportedDatabaseProviders.Sqlite)
|
||||||
|
{
|
||||||
|
var connectionStringBuilder = new SqliteConnectionStringBuilder(database.ConnectionString);
|
||||||
|
|
||||||
|
var existingFileInfo = new FileInfo(connectionStringBuilder.DataSource);
|
||||||
|
|
||||||
|
// Should we require that the existing file actually exists?
|
||||||
|
|
||||||
|
var newFileInfo = new FileInfo(Path.Join(existingFileInfo.DirectoryName, $"{DatabaseName}.{existingFileInfo.Extension}"));
|
||||||
|
|
||||||
|
connectionStringBuilder.DataSource = newFileInfo.FullName;
|
||||||
|
database.ConnectionString = connectionStringBuilder.ConnectionString;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var connectionStringBuilder = new SqlConnectionStringBuilder(database.ConnectionString)
|
||||||
|
{
|
||||||
|
DataSource = DatabaseName
|
||||||
|
};
|
||||||
|
database.ConnectionString = connectionStringBuilder.ConnectionString;
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Settings;
|
||||||
|
using Bit.Infrastructure.Dapper;
|
||||||
|
using Bit.Infrastructure.EntityFramework;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using MySqlConnector;
|
||||||
|
|
||||||
|
namespace Bit.Infrastructure.IntegrationTest.Utilities;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default customization applied to all database tests. If no customizer is added, this is added implicitly.
|
||||||
|
/// </summary>
|
||||||
|
public class DefaultCustomizerAttribute : TestCustomizerAttribute
|
||||||
|
{
|
||||||
|
public static readonly DefaultCustomizerAttribute Instance = new();
|
||||||
|
|
||||||
|
public override Task CustomizeAsync(CustomizationContext customizationContext)
|
||||||
|
{
|
||||||
|
var database = customizationContext.Database;
|
||||||
|
var services = customizationContext.Services;
|
||||||
|
if (!database.Enabled)
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
services.AddLogging(builder =>
|
||||||
|
{
|
||||||
|
builder.AddProvider(new XunitLoggerProvider(LogLevel.Information));
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddDataProtection();
|
||||||
|
|
||||||
|
services.AddSingleton(customizationContext.Database);
|
||||||
|
|
||||||
|
if (database.Type == SupportedDatabaseProviders.SqlServer && !database.UseEf)
|
||||||
|
{
|
||||||
|
services.AddDapperRepositories(false);
|
||||||
|
var globalSettings = new GlobalSettings
|
||||||
|
{
|
||||||
|
DatabaseProvider = "sqlServer",
|
||||||
|
SqlServer = new GlobalSettings.SqlSettings
|
||||||
|
{
|
||||||
|
ConnectionString = database.ConnectionString,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
services.AddSingleton(globalSettings);
|
||||||
|
services.AddSingleton<IGlobalSettings>(globalSettings);
|
||||||
|
services.AddDistributedSqlServerCache((options) =>
|
||||||
|
{
|
||||||
|
options.ConnectionString = database.ConnectionString;
|
||||||
|
options.SchemaName = "dbo";
|
||||||
|
options.TableName = "Cache";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.SetupEntityFramework(database.ConnectionString, database.Type);
|
||||||
|
services.AddPasswordManagerEFRepositories(false);
|
||||||
|
services.AddSingleton<IDistributedCache, EntityFrameworkCache>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Xunit.Sdk;
|
||||||
|
|
||||||
|
namespace Bit.Infrastructure.IntegrationTest.Utilities;
|
||||||
|
|
||||||
|
public class CustomizationContext
|
||||||
|
{
|
||||||
|
// Defaults to Database.Enabled if left as null
|
||||||
|
public bool? Enabled { get; set; }
|
||||||
|
public Database Database { get; }
|
||||||
|
|
||||||
|
public MethodInfo TestMethod { get; }
|
||||||
|
|
||||||
|
public DisposalTracker DisposalTracker { get; }
|
||||||
|
|
||||||
|
public IServiceCollection Services { get; }
|
||||||
|
|
||||||
|
public Func<ServiceProvider, ParameterInfo, object?> ParameterResolver { get; set; } = DefaultParameterResolver;
|
||||||
|
|
||||||
|
|
||||||
|
public CustomizationContext(Database database, MethodInfo testMethod, DisposalTracker disposalTracker)
|
||||||
|
{
|
||||||
|
Database = database;
|
||||||
|
TestMethod = testMethod;
|
||||||
|
DisposalTracker = disposalTracker;
|
||||||
|
Services = new ServiceCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object? DefaultParameterResolver(ServiceProvider services, ParameterInfo parameter)
|
||||||
|
{
|
||||||
|
return services.GetService(parameter.ParameterType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Assembly)]
|
||||||
|
public abstract class TestCustomizerAttribute : Attribute
|
||||||
|
{
|
||||||
|
public abstract Task CustomizeAsync(CustomizationContext customizationContext);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user