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
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System.Globalization;
using EPiServer;
using EPiServer.Commerce.Catalog.ContentTypes;
using EPiServer.Core;
using EPiServer.DataAccess;
using EPiServer.Security;
using Mediachase.Commerce;
using Mediachase.Commerce.Catalog;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Optimizely.TestContainers.Commerce.Tests.Models.Commerce;
using Optimizely.TestContainers.Shared;

namespace Optimizely.TestContainers.Commerce.Tests;

public class CommerceCatalogIntegrationTests() : OptimizelyIntegrationTestBase(includeCommerce: true)
{
protected override void ConfiureWebHostBuilder(IWebHostBuilder webHostBuilder)
{
webHostBuilder.UseStartup<Startup>();
}

[Fact]
public void Can_Save_Catalog_And_Node_And_Product()
{
// Arrange
var referenceConverter = Services.GetRequiredService<ReferenceConverter>();
var contentRepository = Services.GetRequiredService<IContentRepository>();

var rootLink = referenceConverter.GetRootLink();

var aliensCatalog = contentRepository.GetDefault<CatalogContent>(rootLink);
aliensCatalog.Name = "Aliens";
aliensCatalog.DefaultCurrency = Currency.USD;
aliensCatalog.DefaultLanguage = "en";
aliensCatalog.WeightBase = "kgs"; // From WeightBaseSelectionFactory
aliensCatalog.LengthBase = "cm"; // From LengthBaseSelectionFactory

var alienCatalogReference = contentRepository.Save(aliensCatalog, SaveAction.Publish, AccessLevel.NoAccess);

var aliensNode = contentRepository.GetDefault<NodeContent>(alienCatalogReference, CultureInfo.GetCultureInfo("en"));
aliensNode.Name = "NeuralViz Aliens";

// Act
var aliensNodeReference = contentRepository.Save(aliensNode, SaveAction.Publish, AccessLevel.NoAccess);

// Arrange
var testAlienProduct = contentRepository.GetDefault<TestProduct>(aliensNodeReference, CultureInfo.GetCultureInfo("en"));
testAlienProduct.Name = "Snarbo";
testAlienProduct.Description = new XhtmlString("<p>Some scary facts about Aliens!</p>");

// Act
var testAlienProductReference = contentRepository.Save(testAlienProduct, SaveAction.Publish, AccessLevel.NoAccess);

// Assert
Assert.NotNull(aliensNodeReference);
Assert.NotNull(testAlienProductReference);

// Act
aliensNode = contentRepository.Get<NodeContent>(aliensNodeReference);
testAlienProduct = contentRepository.Get<TestProduct>(testAlienProductReference);

// Assert
Assert.Equal("Aliens", aliensCatalog.Name);
Assert.Equal("NeuralViz Aliens", aliensNode.Name);
Assert.Equal("Snarbo", testAlienProduct.Name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.ComponentModel.DataAnnotations;
using EPiServer.Commerce.Catalog.ContentTypes;
using EPiServer.Commerce.Catalog.DataAnnotations;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.DataAnnotations;

namespace Optimizely.TestContainers.Commerce.Tests.Models.Commerce;

[CatalogContentType(
GUID = "0B06DE9B-6AE3-40FB-909E-E718CCC260AE",
DisplayName = "Test Product",
Description = "Test product for integration tests.")]
public class TestProduct : ProductContent
{
[Display(
Name = "Description",
GroupName = SystemTabNames.Content,
Order = 1)]
[Searchable]
[CultureSpecific]
[Tokenize]
[IncludeInDefaultSearch]
public virtual XhtmlString? Description { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="EPiServer.CMS" Version="12.33.1" />
<PackageReference Include="EPiServer.Commerce" Version="14.40.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Testcontainers.MsSql" Version="4.6.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Optimizely.TestContainers.Shared\Optimizely.TestContainers.Shared.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="DefaultSiteContent.episerverdata">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<Folder Include="Models\" />
</ItemGroup>

</Project>
48 changes: 48 additions & 0 deletions Optimizely.TestContainers.Commerce.Tests/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using EPiServer.Cms.Shell;
using EPiServer.Cms.UI.AspNetIdentity;
using EPiServer.Scheduler;
using EPiServer.Web.Routing;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Optimizely.TestContainers.Commerce.Tests;

public class Startup(IWebHostEnvironment webHostingEnvironment)
{
public void ConfigureServices(IServiceCollection services)
{
if (webHostingEnvironment.IsDevelopment())
{
AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(webHostingEnvironment.ContentRootPath, "App_Data"));

services.Configure<SchedulerOptions>(options => options.Enabled = false);
}

services
.AddCmsAspNetIdentity<ApplicationUser>()
.AddCms()
.AddCommerce()
.AddAdminUserRegistration()
.AddEmbeddedLocalization<Startup>();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapContent();
});
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="EPiServer.CMS" Version="12.33.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Testcontainers.MsSql" Version="4.6.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>

<ItemGroup>
<None Update="DefaultSiteContent.episerverdata">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
117 changes: 117 additions & 0 deletions Optimizely.TestContainers.Shared/OptimizelyIntegrationTestBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using EPiServer.Data;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Testcontainers.MsSql;

namespace Optimizely.TestContainers.Shared;

public abstract class OptimizelyIntegrationTestBase(bool includeCommerce) : IAsyncLifetime
{
private IHost _host = null!;

// Since we use same container with different db names we can remove one of these :P
private MsSqlContainer _databaseContainer = null!;

protected IServiceProvider Services { get; private set; } = null!;

public virtual async Task InitializeAsync()
{
// Create Cms SQL Server container
var container = await CreateDatabaseContainer();

// Create CMS databse
var cmsDatabaseConnectionString = await CreateNamedDatabaseConnectionString(container, "Cms");

string? commerceDatabaseConnectionString = null;
if (includeCommerce)
{
commerceDatabaseConnectionString = await CreateNamedDatabaseConnectionString(container, "Commerce");
}


// Build CMS host
_host = Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webHostBuilder =>
{
webHostBuilder
.ConfigureServices((context, services) =>
{
// TODO: Only include in CMS test
// Add data importer service to setup default content for the tests
//services.AddTransient<OptimizelyDataImporter>();

// Must be set here too for initialization to work for CMS
services.Configure<DataAccessOptions>(o =>
{
o.SetConnectionString(cmsDatabaseConnectionString);
});
})
.ConfigureAppConfiguration((context, configBuilder) =>
{
var testSettings = new Dictionary<string, string?>
{
["ConnectionStrings:EPiServerDB"] = cmsDatabaseConnectionString,
["ConnectionStrings:EcfSqlConnection"] = commerceDatabaseConnectionString,
};

configBuilder.AddInMemoryCollection(testSettings);
});

// To configure aps separately with Cms and Commerce Statup files in separate projects
ConfiureWebHostBuilder(webHostBuilder);
})
.ConfigureCmsDefaults()
.Build();

// Run initialization engine (simulate application startup)
var initializer = _host.Services.GetRequiredService<InitializationEngine>();
if (initializer.InitializationState != InitializationState.Initialized)
initializer.Initialize();

Services = _host.Services;

await _host.StartAsync();
}

protected abstract void ConfiureWebHostBuilder(IWebHostBuilder webHostBuilder);

public async Task DisposeAsync()
{
await _host.StopAsync();

await _databaseContainer.DisposeAsync();
}

private async Task<MsSqlContainer> CreateDatabaseContainer()
{
var container = new MsSqlBuilder()
.WithImage("mcr.microsoft.com/mssql/server:2022-latest")
.WithPassword("yourStrong(!)Password")
.Build();

await container.StartAsync();

_databaseContainer = container;

return _databaseContainer;
}

private async Task<string> CreateNamedDatabaseConnectionString(MsSqlContainer container, string databaseName)
{
databaseName = $"{GetType().Name}-{databaseName}";

var masterConnectionString = container.GetConnectionString();
await using var connection = new SqlConnection(masterConnectionString);
await connection.OpenAsync();
await using var command = new SqlCommand($"CREATE DATABASE [{databaseName}]", connection);
await command.ExecuteNonQueryAsync();

// Workaround to set separate database names inside container
return masterConnectionString.Replace("master", databaseName);
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
18 changes: 12 additions & 6 deletions OptimizelyTestContainers.sln
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Optimizely.TestContainers", "src\Web\Optimizely.TestContainers.csproj", "{E65E2A81-3213-498F-80B0-4C12CF2CBB6C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OptimizelyTestContainers.Tests", "test\OptimizelyTestContainers.Tests\OptimizelyTestContainers.Tests.csproj", "{60DAC0B9-1D46-4D3A-BC27-4B7BE193AB4E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Optimizely.TestContainers.Shared", "Optimizely.TestContainers.Shared\Optimizely.TestContainers.Shared.csproj", "{E4204C7A-7CC7-40FB-BFE2-D36B7286D7D3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Optimizely.TestContainers.Commerce.Tests", "Optimizely.TestContainers.Commerce.Tests\Optimizely.TestContainers.Commerce.Tests.csproj", "{63D88C12-0DF6-4C82-939C-1FF0B564B63E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E65E2A81-3213-498F-80B0-4C12CF2CBB6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E65E2A81-3213-498F-80B0-4C12CF2CBB6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E65E2A81-3213-498F-80B0-4C12CF2CBB6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E65E2A81-3213-498F-80B0-4C12CF2CBB6C}.Release|Any CPU.Build.0 = Release|Any CPU
{60DAC0B9-1D46-4D3A-BC27-4B7BE193AB4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{60DAC0B9-1D46-4D3A-BC27-4B7BE193AB4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60DAC0B9-1D46-4D3A-BC27-4B7BE193AB4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60DAC0B9-1D46-4D3A-BC27-4B7BE193AB4E}.Release|Any CPU.Build.0 = Release|Any CPU
{E4204C7A-7CC7-40FB-BFE2-D36B7286D7D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E4204C7A-7CC7-40FB-BFE2-D36B7286D7D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E4204C7A-7CC7-40FB-BFE2-D36B7286D7D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E4204C7A-7CC7-40FB-BFE2-D36B7286D7D3}.Release|Any CPU.Build.0 = Release|Any CPU
{63D88C12-0DF6-4C82-939C-1FF0B564B63E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{63D88C12-0DF6-4C82-939C-1FF0B564B63E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{63D88C12-0DF6-4C82-939C-1FF0B564B63E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{63D88C12-0DF6-4C82-939C-1FF0B564B63E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
Loading