From a9c7e1cc9449b7263e9f13f294d61a033e9d8a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pozler?= Date: Wed, 18 Oct 2023 01:53:15 +0200 Subject: [PATCH] tests rewritten using xUnit library --- EvitaDB.TestX/BaseTest.cs | 33 + EvitaDB.TestX/EvitaClientDemoQueryTest.cs | 210 +++++ EvitaDB.TestX/EvitaClientReadTest.cs | 361 +++++++++ EvitaDB.TestX/EvitaClientTestX.cs | 60 -- EvitaDB.TestX/EvitaClientWriteTest.cs | 815 ++++++++++++++++++++ EvitaDB.TestX/EvitaDB.TestX.csproj | 2 +- EvitaDB.TestX/SetupFixture.cs | 56 +- EvitaDB.TestX/Utils/DataManipulationUtil.cs | 10 +- 8 files changed, 1455 insertions(+), 92 deletions(-) create mode 100644 EvitaDB.TestX/BaseTest.cs create mode 100644 EvitaDB.TestX/EvitaClientDemoQueryTest.cs create mode 100644 EvitaDB.TestX/EvitaClientReadTest.cs delete mode 100644 EvitaDB.TestX/EvitaClientTestX.cs create mode 100644 EvitaDB.TestX/EvitaClientWriteTest.cs diff --git a/EvitaDB.TestX/BaseTest.cs b/EvitaDB.TestX/BaseTest.cs new file mode 100644 index 0000000..25bbff3 --- /dev/null +++ b/EvitaDB.TestX/BaseTest.cs @@ -0,0 +1,33 @@ +using EvitaDB.Client; +using Xunit.Abstractions; + +namespace EvitaDB.TestX; + +public abstract class BaseTest : IClassFixture, IAsyncLifetime +{ + protected readonly ITestOutputHelper _outputHelper; + protected readonly SetupFixture _setupFixture; + + protected EvitaClient? _client; + + private const int RandomSeed = 42; + protected static readonly Random Random = new(RandomSeed); + protected const string DateTimeFormat = "yyyy-MM-dd HH:mm:ss zzz"; + + public BaseTest(ITestOutputHelper outputHelper, SetupFixture setupFixture) + { + _outputHelper = outputHelper; + _setupFixture = setupFixture; + } + + public async Task InitializeAsync() + { + _client = await _setupFixture.GetClient(); + } + + public Task DisposeAsync() + { + _setupFixture.ReturnClient(_client!); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/EvitaDB.TestX/EvitaClientDemoQueryTest.cs b/EvitaDB.TestX/EvitaClientDemoQueryTest.cs new file mode 100644 index 0000000..c5ef3d7 --- /dev/null +++ b/EvitaDB.TestX/EvitaClientDemoQueryTest.cs @@ -0,0 +1,210 @@ +using System.Globalization; +using EvitaDB.Client; +using EvitaDB.Client.Config; +using EvitaDB.Client.DataTypes; +using EvitaDB.Client.Models; +using EvitaDB.Client.Models.Data; +using EvitaDB.Client.Models.Data.Structure; +using EvitaDB.Client.Queries.Order; +using EvitaDB.Client.Queries.Requires; +using EvitaDB.TestX.Utils; +using static EvitaDB.Client.Queries.IQueryConstraints; + +namespace EvitaDB.TestX; + +public class EvitaClientDemoQueryTest : IDisposable +{ + private static readonly EvitaClientConfiguration? EvitaClientConfiguration = new EvitaClientConfiguration.Builder() + .SetHost("demo.evitadb.io") + .SetPort(5556) + .SetUseGeneratedCertificate(false) + .SetUsingTrustedRootCaCertificate(true) + .Build(); + + private static EvitaClient? _client; + + private const string ExistingCatalogWithData = "evita"; + + public EvitaClientDemoQueryTest() + { + _client = new EvitaClient(EvitaClientConfiguration!); + } + + [Fact] + public void ShouldBeAbleToQueryCatalogWithDataAndGetDataChunkOfEntityReferences() + { + EvitaEntityReferenceResponse referenceResponse = _client!.QueryCatalog(ExistingCatalogWithData, + session => session.Query( + Query( + Collection("Product"), + FilterBy( + And( + Not( + AttributeContains("url", "bla") + ), + Or( + EntityPrimaryKeyInSet(677, 678, 679, 680), + And( + PriceBetween(1.2m, 1000), + PriceValidIn(DateTimeOffset.Now), + PriceInPriceLists("basic", "vip"), + PriceInCurrency(new Currency("CZK")) + ) + ) + ) + ), + OrderBy( + PriceNatural(OrderDirection.Desc) + ), + Require( + Page(1, 20), + DataInLocales(new CultureInfo("en-US"), new CultureInfo("cs-CZ")), + QueryTelemetry() + ) + ) + )); + + Assert.Equal(20, referenceResponse.RecordPage.Data!.Count); + Assert.True(referenceResponse.RecordPage.Data.All(x => x is {Type: "Product", PrimaryKey: > 0})); + Assert.Equal(1, referenceResponse.ExtraResults.Count); + Assert.Equal(typeof(Client.Models.ExtraResults.QueryTelemetry), referenceResponse.ExtraResults.Values.ToList()[0].GetType()); + } + + [Fact] + public void ShouldBeAbleToQueryCatalogWithDataAndGetDataChunkOfSealedEntities() + { + EvitaEntityResponse entityResponse = _client!.QueryCatalog(ExistingCatalogWithData, session => + session.Query( + Query( + Collection("Product"), + FilterBy( + And( + Not( + AttributeContains("url", "bla") + ), + Or( + EntityPrimaryKeyInSet(677, 678, 679, 680), + And( + PriceBetween(102.2m, 10000), + PriceValidIn(DateTimeOffset.Now), + PriceInPriceLists("basic", "vip"), + PriceInCurrency(new Currency("CZK")) + ) + ) + ) + ), + OrderBy( + PriceNatural(OrderDirection.Desc) + ), + Require( + Page(1, 20), + EntityFetch(AttributeContentAll(), ReferenceContentAll(), PriceContentAll()), + DataInLocales(new CultureInfo("en-US"), new CultureInfo("cs-CZ")), + QueryTelemetry() + ) + ) + )); + + Assert.Equal(20, entityResponse.RecordPage.Data!.Count); + Assert.Contains(entityResponse.RecordPage.Data, x => x.GetAttributeValues().Any()); + Assert.Contains(entityResponse.RecordPage.Data, x => x.GetReferences().Any()); + Assert.Contains(entityResponse.RecordPage.Data, x => x.GetPrices().Any()); + + Assert.Equal(1, entityResponse.ExtraResults.Count); + Assert.Equal(typeof(Client.Models.ExtraResults.QueryTelemetry), entityResponse.ExtraResults.Values.ToList()[0].GetType()); + } + + [Fact] + public void ShouldBeAbleToExecuteComplexQueryAndGetResults() + { + EvitaEntityResponse evitaEntityResponse = _client!.QueryCatalog(ExistingCatalogWithData, + session => session.Query( + Query( + Collection("Product"), + FilterBy( + Or( + AttributeInSet("visibility", "yes", "no"), + EntityLocaleEquals(new CultureInfo("cs-CZ")), + HierarchyWithin("categories", null, ExcludingRoot()), + Not( + ReferenceHaving( + "groups", + And( + AttributeInRange("assignmentValidity", DateTimeOffset.Now), + AttributeInRange("assignmentValidity", DateTimeOffset.Now.AddDays(7)) + ) + ) + ), + And( + PriceInPriceLists("vip", "basic"), + PriceInCurrency("CZK"), + PriceBetween(100m, 200.5m), + PriceValidNow() + ), + AttributeBetween("frekvence-od", 20m, 95.3m), + UserFilter( + FacetHaving("variantParameters", EntityPrimaryKeyInSet(1, 2, 3)) + ) + )), + OrderBy( + AttributeNatural("orderedQuantity", OrderDirection.Desc), + PriceNatural(OrderDirection.Asc), + ReferenceProperty( + "groups", Random() + ) + ), + Require( + EntityFetch( + AssociatedDataContentAll(), + AttributeContentAll(), + PriceContentAll(), + ReferenceContentWithAttributes( + "relatedProducts", + FilterBy(AttributeContains("category", "w")), + OrderBy(EntityProperty(AttributeNatural("orderedQuantity", OrderDirection.Asc))), + EntityFetch(AttributeContentAll()) + ), + HierarchyContent(StopAt(Distance(2)), EntityFetch(AttributeContentAll())) + ), + FacetSummaryOfReference( + "parameterValues", + FacetStatisticsDepth.Impact, + FilterBy(AttributeContains("code", "a")), + OrderBy(AttributeNatural(Data.AttributeName, OrderDirection.Desc)) + ), + FacetGroupsDisjunction("productSetItems", FilterBy(AttributeGreaterThanEquals("order", 5))), + AttributeHistogram(20, "response-time", "thickness"), + PriceHistogram(10), + QueryTelemetry(), + HierarchyOfReference( + "categories", + FromNode( + "x", + Node(FilterBy(AttributeEquals("code", "portables"))), + EntityFetch(AttributeContent("categoryType")), + StopAt(Distance(1)), + Statistics(StatisticsType.ChildrenCount, StatisticsType.QueriedEntityCount) + ), + FromNode( + "y", + Node(FilterBy(AttributeContains("code", "laptops"))), + EntityFetch(AttributeContent("status")), + StopAt(Distance(2)), + Statistics(StatisticsType.ChildrenCount, StatisticsType.QueriedEntityCount) + ) + ), + PriceType(QueryPriceMode.WithoutTax), + Strip(0, 20) + ) + ) + ) + ); + + Assert.True(evitaEntityResponse.RecordData.Count > 0); + } + + public void Dispose() + { + _client?.Dispose(); + } +} \ No newline at end of file diff --git a/EvitaDB.TestX/EvitaClientReadTest.cs b/EvitaDB.TestX/EvitaClientReadTest.cs new file mode 100644 index 0000000..3f7f54f --- /dev/null +++ b/EvitaDB.TestX/EvitaClientReadTest.cs @@ -0,0 +1,361 @@ +using EvitaDB.Client; +using EvitaDB.Client.Exceptions; +using EvitaDB.Client.Models; +using EvitaDB.Client.Models.Data; +using EvitaDB.Client.Models.Data.Structure; +using EvitaDB.Client.Models.ExtraResults; +using EvitaDB.Client.Models.Schemas; +using EvitaDB.Client.Queries.Requires; +using EvitaDB.TestX.Utils; +using FluentAssertions; +using Xunit.Abstractions; +using static EvitaDB.Client.Queries.IQueryConstraints; + +namespace EvitaDB.TestX; + +public class EvitaClientReadTest : BaseTest +{ + public EvitaClientReadTest(ITestOutputHelper outputHelper, SetupFixture setupFixture) + : base(outputHelper, setupFixture) + { + } + + [Fact] + public void ShouldQueryCatalog() + { + ICatalogSchema catalogSchema = _client!.QueryCatalog( + Data.TestCatalog, + x => x.GetCatalogSchema() + ); + Assert.NotNull(catalogSchema); + Assert.Equal(Data.TestCatalog, catalogSchema.Name); + } + + [Fact] + public void ShouldQueryOneEntityReference() + { + EntityReference entityReference = _client!.QueryCatalog( + Data.TestCatalog, + session => session.QueryOneEntityReference( + Query( + Collection(Entities.Product), + FilterBy( + EntityPrimaryKeyInSet(1) + ) + ) + ) ?? throw new Exception("Entity reference not found!")); + Assert.NotNull(entityReference); + Assert.Equal(Entities.Product, entityReference.Type); + Assert.Equal(1, entityReference.PrimaryKey); + } + + [Fact] + public void ShouldNotQueryOneMissingEntity() + { + EntityReference? entityReference = _client!.QueryCatalog( + Data.TestCatalog, + session => session.QueryOneEntityReference( + Query( + Collection(Entities.Product), + FilterBy( + EntityPrimaryKeyInSet(-100) + ) + ) + )); + Assert.Null(entityReference); + } + + [Fact] + public void ShouldQueryOneSealedEntity() + { + IList products = _setupFixture.CreatedEntities[Entities.Product]; + int primaryKey = products.ElementAt(Random.Next(products.Count)).PrimaryKey!.Value; + ISealedEntity sealedEntity = _client!.QueryCatalog( + Data.TestCatalog, + session => session.QueryOneSealedEntity( + Query( + Collection(Entities.Product), + FilterBy( + EntityPrimaryKeyInSet(primaryKey) + ), + Require( + EntityFetch( + HierarchyContent(), + AttributeContentAll(), + AssociatedDataContentAll(), + PriceContentAll(), + ReferenceContentAll(), + DataInLocalesAll() + ) + ) + ) + ) ?? throw new EvitaInvalidUsageException("Entity not found")); + + Assert.NotNull(sealedEntity); + Assert.Equal(Entities.Product, sealedEntity.Type); + products.Single(x => x.PrimaryKey == primaryKey).Should().BeEquivalentTo(sealedEntity, options => options.Excluding(x=>x.ParentEntity).Excluding(x=>x.Parent)); + } + + [Fact] + public void ShouldQueryListOfEntityReferences() + { + int[] requestedIds = { 1, 2, 5 }; + IList entityReferences = _client!.QueryCatalog( + Data.TestCatalog, + session => session.QueryListOfEntityReferences( + Query( + Collection(Entities.Product), + FilterBy( + EntityPrimaryKeyInSet(requestedIds) + ) + ) + )); + + Assert.NotNull(entityReferences); + Assert.Equal(3, entityReferences.Count); + + for (int i = 0; i < entityReferences.Count; i++) + { + EntityReference entityReference = entityReferences.ElementAt(i); + Assert.Equal(Entities.Product, entityReference.Type); + Assert.Equal(requestedIds[i], entityReference.PrimaryKey); + } + } + + [Fact] + public void ShouldQueryListOfSealedEntities() + { + int[] requestedIds = { 1, 2, 5 }; + IList products = _setupFixture.CreatedEntities[Entities.Product]; + IList sealedEntities = _client!.QueryCatalog( + Data.TestCatalog, + session => session.QueryListOfSealedEntities( + Query( + Collection(Entities.Product), + FilterBy( + EntityPrimaryKeyInSet(requestedIds) + ), + Require( + EntityFetchAll() + ) + ) + )); + + Assert.NotNull(sealedEntities); + Assert.Equal(3, sealedEntities.Count); + + for (int i = 0; i < sealedEntities.Count; i++) + { + ISealedEntity sealedEntity = sealedEntities.ElementAt(i); + Assert.Equal(Entities.Product, sealedEntity.Type); + Assert.Equal(requestedIds[i], sealedEntity.PrimaryKey); + Assert.Equal(products.Single(x => x.PrimaryKey == requestedIds[i]), sealedEntity); + } + } + + [Fact] + public void ShouldGetListWithExtraResults() + { + ISealedEntity? someProductWithCategory = _setupFixture.CreatedEntities[Entities.Product] + .Where(it => it.GetReferences(Data.ReferenceCategories).Any()) + .FirstOrDefault(it => it.GetAllPricesForSale().Count > 0); + IList allPricesForSale = someProductWithCategory!.GetAllPricesForSale(); + EvitaResponse result = _client!.QueryCatalog( + Data.TestCatalog, + session => + { + return session.QuerySealedEntity( + Query( + Collection(Entities.Product), + FilterBy( + PriceInPriceLists(allPricesForSale.Select(x => x.PriceList) + .ToArray()), + PriceInCurrency(allPricesForSale.Select(x => x.Currency) + .First()), + EntityLocaleEquals(someProductWithCategory.GetAllLocales().First()) + ), + Require( + EntityFetchAll(), + QueryTelemetry(), + PriceHistogram(20), + AttributeHistogram(20, Data.AttributeQuantity), + HierarchyOfReference( + Data.ReferenceCategories, + FromRoot(Data.HierarchyReferenceRoot, EntityFetchAll()) + ), + FacetSummary(FacetStatisticsDepth.Impact) + ) + ) + ); + } + ); + + Assert.NotNull(result); + Assert.True(result.RecordPage.TotalRecordCount > 0); + + Assert.NotNull(result.GetExtraResult()); + + Client.Models.ExtraResults.PriceHistogram? priceHistogram = result.GetExtraResult(); + Assert.NotNull(priceHistogram); + Assert.True(priceHistogram.Max.CompareTo(priceHistogram.Min) >= 0); + Assert.True(priceHistogram.Buckets.Length > 0); + Assert.True(priceHistogram.Min.CompareTo(0m) > 0); + + Client.Models.ExtraResults.AttributeHistogram? attributeHistogram = + result.GetExtraResult(); + Assert.NotNull(attributeHistogram); + IHistogram? theHistogram = attributeHistogram.GetHistogram(Data.AttributeQuantity); + Assert.NotNull(theHistogram); + Assert.True(theHistogram.Max.CompareTo(theHistogram.Min) >= 0); + Assert.True(theHistogram.Buckets.Length > 0); + Assert.True(theHistogram.Min.CompareTo(0m) > 0); + + Hierarchy? hierarchy = result.GetExtraResult(); + Assert.NotNull(hierarchy); + IDictionary>? categoryHierarchy = + hierarchy.GetReferenceHierarchy(Data.ReferenceCategories); + Assert.NotNull(categoryHierarchy); + Assert.True(categoryHierarchy[Data.HierarchyReferenceRoot].Count >= 0); + + Client.Models.ExtraResults.FacetSummary? facetSummary = + result.GetExtraResult(); + Assert.NotNull(facetSummary); + Assert.True(facetSummary.GetFacetGroupStatistics().Count > 0); + } + + [Fact] + public void ShouldGetSingleEntity() + { + ISealedEntity? sealedEntity = _client!.QueryCatalog( + Data.TestCatalog, + session => session.GetEntity( + Entities.Product, + 7, + EntityFetchAll().Requirements! + )); + + Assert.NotNull(sealedEntity); + + Assert.Equal(Entities.Product, sealedEntity.Type); + Assert.Equal(7, sealedEntity.PrimaryKey); + Assert.Equal(_setupFixture.CreatedEntities[Entities.Product].Single(x => x.PrimaryKey == 7), sealedEntity); + } + + [Fact] + public void ShouldEnrichSingleEntity() + { + IList products = _setupFixture.CreatedEntities[Entities.Product]; + ISealedEntity? sealedEntity = _client!.QueryCatalog( + Data.TestCatalog, + session => session.GetEntity( + Entities.Product, + 7, + AttributeContent() + )); + + Assert.Equal(Entities.Product, sealedEntity!.Type); + Assert.Equal(7, sealedEntity.PrimaryKey); + products.Single(x => x.PrimaryKey == 7).Should().NotBeEquivalentTo(sealedEntity, options => options.Excluding(x=>x.ParentEntity).Excluding(x=>x.Parent)); + + ISealedEntity? enrichedEntity = _client.QueryCatalog( + Data.TestCatalog, + session => session.GetEntity( + Entities.Product, + 7, + EntityFetchAll().Requirements! + )); + + Assert.Equal(Entities.Product, enrichedEntity!.Type); + Assert.Equal(7, enrichedEntity.PrimaryKey); + + ISealedEntity entityToCompare = products.Single(x => x.PrimaryKey == 7); + + entityToCompare.Should().BeEquivalentTo(entityToCompare); + } + + [Fact] + public void ShouldLimitSingleEntity() + { + IList products = _setupFixture.CreatedEntities[Entities.Product]; + ISealedEntity? sealedEntity = _client!.QueryCatalog( + Data.TestCatalog, + session => session.GetEntity( + Entities.Product, + 7, + EntityFetchAll().Requirements! + )); + + Assert.Equal(Entities.Product, sealedEntity!.Type); + Assert.Equal(7, sealedEntity.PrimaryKey); + products.Single(x => x.PrimaryKey == 7).Should().BeEquivalentTo(sealedEntity, options => options.Excluding(x=>x.ParentEntity).Excluding(x=>x.Parent)); + + ISealedEntity? limitedEntity = _client.QueryCatalog( + Data.TestCatalog, + session => session.GetEntity( + Entities.Product, + 7, + AttributeContent() + )); + + Assert.Equal(Entities.Product, limitedEntity!.Type); + Assert.Equal(7, limitedEntity.PrimaryKey); + products.Single(x => x.PrimaryKey == 7).Should().NotBeEquivalentTo(limitedEntity, options => options.Excluding(x=>x.ParentEntity).Excluding(x=>x.Parent)); + } + + [Fact] + public void ShouldRetrieveCollectionSize() + { + int productCount = _client!.QueryCatalog( + Data.TestCatalog, + session => session.GetEntityCollectionSize(Entities.Product)); + + Assert.Equal(_setupFixture.CreatedEntities[Entities.Product].Count, productCount); + } + + [Fact] + public void ShouldQueryListOfSealedEntitiesEvenWithoutProperRequirements() + { + IList sealedEntities = _client!.QueryCatalog( + Data.TestCatalog, + session => session.QueryListOfSealedEntities( + Query( + Collection(Entities.Product), + FilterBy( + EntityPrimaryKeyInSet(1, 2, 5) + ) + ) + )); + Assert.Equal(3, sealedEntities.Count); + } + + [Fact] + public void ShouldListCatalogNames() + { + ISet catalogNames = ListCatalogNames(_client!); + _outputHelper.WriteLine(string.Join(", ", catalogNames)); + Assert.Equal(1, catalogNames.Count); + Assert.Contains(Data.TestCatalog, catalogNames); + } + + [Fact] + public void ShouldBeAbleToRunParallelClients() + { + EvitaClient anotherParallelClient = new EvitaClient(_client!.Configuration); + _ = ListCatalogNames(anotherParallelClient); + _ = ListCatalogNames(_client); + } + + private static ISet ListCatalogNames(EvitaClient client) + { + return client.GetCatalogNames(); + } + + /*[Fact] + public void ShouldTestCdc() + { + IObservable captures = + _client!.RegisterSystemChangeCapture(new ChangeSystemCaptureRequest(CaptureContent.Header)); + IDisposable subscription = captures.Subscribe(c => { _outputHelper.WriteLine(c.Operation.ToString()); }); + subscription.Dispose(); + }*/ +} \ No newline at end of file diff --git a/EvitaDB.TestX/EvitaClientTestX.cs b/EvitaDB.TestX/EvitaClientTestX.cs deleted file mode 100644 index 06dd4dc..0000000 --- a/EvitaDB.TestX/EvitaClientTestX.cs +++ /dev/null @@ -1,60 +0,0 @@ -using EvitaDB.Client; -using EvitaDB.Client.Models.Schemas; -using EvitaDB.TestX.Utils; -using Xunit.Abstractions; - -namespace EvitaDB.TestX; - -public class EvitaClientTestX : IClassFixture, IAsyncLifetime -{ - private readonly ITestOutputHelper _outputHelper; - private readonly SetupFixture _setupFixture; - - private EvitaClient? _client; - - private const int RandomSeed = 42; - - public EvitaClientTestX(ITestOutputHelper outputHelper, SetupFixture setupFixture) - { - _outputHelper = outputHelper; - _setupFixture = setupFixture; - } - - [Fact] - public void ShouldBeAbleToRunParallelClients() - { - EvitaClient anotherParallelClient = new EvitaClient(_client!.Configuration); - _ = ListCatalogNames(anotherParallelClient); - _ = ListCatalogNames(_client); - } - - [Fact] - public void ShouldBeAbleToFetchNonCachedEntitySchemaFromCatalogSchema() - { - EvitaClient clientWithEmptyCache = new EvitaClient(_client!.Configuration); - clientWithEmptyCache.QueryCatalog( - Data.TestCatalog, - session => - { - IEntitySchema? productSchema = session.GetCatalogSchema().GetEntitySchema(Entities.Product); - Assert.NotNull(productSchema); - } - ); - } - - private static ISet ListCatalogNames(EvitaClient client) - { - return client.GetCatalogNames(); - } - - public async Task InitializeAsync() - { - _client = await _setupFixture.GetClient(); - } - - public Task DisposeAsync() - { - _setupFixture.ReturnClient(_client!); - return Task.CompletedTask; - } -} \ No newline at end of file diff --git a/EvitaDB.TestX/EvitaClientWriteTest.cs b/EvitaDB.TestX/EvitaClientWriteTest.cs new file mode 100644 index 0000000..ba2fdaf --- /dev/null +++ b/EvitaDB.TestX/EvitaClientWriteTest.cs @@ -0,0 +1,815 @@ +using System.Globalization; +using EvitaDB.Client; +using EvitaDB.Client.DataTypes; +using EvitaDB.Client.Exceptions; +using EvitaDB.Client.Models.Data; +using EvitaDB.Client.Models.Data.Mutations; +using EvitaDB.Client.Models.Data.Mutations.Attributes; +using EvitaDB.Client.Models.Data.Structure; +using EvitaDB.Client.Models.Schemas; +using EvitaDB.Client.Models.Schemas.Mutations.Attributes; +using EvitaDB.Client.Models.Schemas.Mutations.Catalogs; +using EvitaDB.Client.Session; +using EvitaDB.TestX.Utils; +using Xunit.Abstractions; +using static EvitaDB.Client.Queries.IQueryConstraints; + +namespace EvitaDB.TestX; + +public class EvitaClientWriteTest : BaseTest +{ + public EvitaClientWriteTest(ITestOutputHelper outputHelper, SetupFixture setupFixture) + : base(outputHelper, setupFixture) + { + } + + [Fact] + public void ShouldBeAbleToCreateCatalogAndEntitySchemaAndInsertNewEntityWithAttribute() + { + string testCollection = "testingCollection"; + string attributeDateTime = "attrDateTime"; + string attributeDecimalRange = "attrDecimalRange"; + string nonExistingAttribute = "nonExistingAttribute"; + + // delete test catalog if it exists + _client!.DeleteCatalogIfExists(Data.TestCatalog); + + // define new catalog + ICatalogSchema catalogSchema = _client.DefineCatalog(Data.TestCatalog).ToInstance(); + Assert.Equal(Data.TestCatalog, catalogSchema.Name); + + using (EvitaClientSession rwSession = _client.CreateReadWriteSession(Data.TestCatalog)) + { + // create a new entity schema + catalogSchema = rwSession.UpdateAndFetchCatalogSchema(new CreateEntitySchemaMutation(testCollection)); + + Assert.NotNull(catalogSchema.GetEntitySchema(testCollection)); + Assert.Equal(1, catalogSchema.GetEntitySchema(testCollection)!.Version); + Assert.Equal(2, catalogSchema.Version); + + // create two attributes schema mutations + CreateAttributeSchemaMutation createAttributeDateTime = new CreateAttributeSchemaMutation( + attributeDateTime, nameof(attributeDateTime), null, false, true, true, false, true, + typeof(DateTimeOffset), null, 0 + ); + CreateAttributeSchemaMutation createAttributeDecimalRange = new CreateAttributeSchemaMutation( + attributeDecimalRange, nameof(attributeDecimalRange), null, false, true, true, false, true, + typeof(DecimalNumberRange), null, 2 + ); + + // add the two attributes to the entity schema + catalogSchema = rwSession.UpdateAndFetchCatalogSchema( + new ModifyEntitySchemaMutation(testCollection, + createAttributeDateTime, createAttributeDecimalRange) + ); + Assert.Equal(2, catalogSchema.Version); + Assert.Equal(3, catalogSchema.GetEntitySchema(testCollection)!.Version); + + // check if the entity schema has the two attributes + ISealedEntitySchema? entitySchema = rwSession.GetEntitySchema(testCollection); + Assert.NotNull(entitySchema); + Assert.Equal(2, entitySchema.Attributes.Count); + Assert.Equal(3, entitySchema.Version); + Assert.True(entitySchema.Attributes.ContainsKey(attributeDateTime)); + Assert.Equal(typeof(DateTimeOffset), entitySchema.Attributes[attributeDateTime].Type); + Assert.True(entitySchema.Attributes.ContainsKey(attributeDecimalRange)); + Assert.Equal(typeof(DecimalNumberRange), entitySchema.Attributes[attributeDecimalRange].Type); + + // close the session and switch catalog to the alive state + rwSession.GoLiveAndClose(); + } + + using EvitaClientSession newSession = _client.CreateReadWriteSession(Data.TestCatalog); + + // insert a new entity with one of attributes defined in the entity schema + DateTimeOffset dateTimeNow = DateTimeOffset.Now; + ISealedEntity newEntity = newSession.UpsertAndFetchEntity( + new EntityUpsertMutation( + testCollection, + null, + EntityExistence.MayExist, + new UpsertAttributeMutation(attributeDateTime, dateTimeNow) + ), + AttributeContent() + ); + + Assert.Equal(2, newEntity.Schema.Attributes.Count); + Assert.Contains(attributeDateTime, newEntity.GetAttributeNames()); + Assert.Equal(dateTimeNow.ToString(DateTimeFormat), + (newEntity.GetAttribute(attributeDateTime) as DateTimeOffset?)?.ToString(DateTimeFormat)); + + // insert a new entity with attribute that is not defined in the entity schema + ISealedEntity notInAttributeSchemaEntity = newSession.UpsertAndFetchEntity( + new EntityUpsertMutation( + testCollection, + null, + EntityExistence.MayExist, + new UpsertAttributeMutation(nonExistingAttribute, true) + ), + AttributeContent() + ); + + // schema of the entity should have 3 attributes + Assert.Equal(3, notInAttributeSchemaEntity.Schema.Attributes.Count); + Assert.Contains(nonExistingAttribute, notInAttributeSchemaEntity.GetAttributeNames()); + Assert.Equal(true, notInAttributeSchemaEntity.GetAttribute(nonExistingAttribute)); + } + + [Fact] + public void ShouldAllowCreatingCatalogAlongWithTheSchema() + { + string someCatalogName = "differentCatalog"; + try + { + _client!.DefineCatalog(someCatalogName) + .WithDescription("Some description.") + .UpdateVia(_client.CreateReadWriteSession(someCatalogName)); + Assert.Contains(someCatalogName, _client.GetCatalogNames()); + } + finally + { + _client!.DeleteCatalogIfExists(someCatalogName); + } + } + + [Fact] + public void ShouldAllowCreatingCatalogAndEntityCollectionsInPrototypingMode() + { + string someCatalogName = "differentCatalog"; + CultureInfo locale = Data.EnglishLocale; + try + { + _client!.DefineCatalog(someCatalogName) + .WithDescription("This is a tutorial catalog.") + .UpdateViaNewSession(_client); + Assert.Contains(someCatalogName, _client.GetCatalogNames()); + _client.UpdateCatalog( + someCatalogName, + session => + { + session.CreateNewEntity(Entities.Brand, 1) + .SetAttribute(Data.AttributeName, locale, "Lenovo") + .UpsertVia(session); + + ISealedEntitySchema? brand = session.GetEntitySchema(Entities.Brand); + Assert.NotNull(brand); + + IAttributeSchema? nameAttribute = brand.GetAttribute(Data.AttributeName); + Assert.NotNull(nameAttribute); + Assert.True(nameAttribute.Localized); + + // now create an example category tree + session.CreateNewEntity(Entities.Category, 10) + .SetAttribute(Data.AttributeName, locale, "Electronics") + .UpsertVia(session); + + session.CreateNewEntity(Entities.Category, 11) + .SetAttribute(Data.AttributeName, locale, "Laptops") + // laptops will be a child category of electronics + .SetParent(10) + .UpsertVia(session); + + // finally, create a product + session.CreateNewEntity(Entities.Product) + // with a few attributes + .SetAttribute(Data.AttributeName, locale, "ThinkPad P15 Gen 1") + .SetAttribute(Data.AttributeCores, 8) + .SetAttribute(Data.AttributeGraphics, "NVIDIA Quadro RTX 4000 with Max-Q Design") + // and price for sale + .SetPrice( + 1, Data.PriceListBasic, + Data.CurrencyUsd, + 1420m, 20m, 1704m, + true + ) + // link it to the manufacturer + .SetReference( + Data.ReferenceBrand, Entities.Brand, + Cardinality.ExactlyOne, + 1 + ) + // and to the laptop category + .SetReference( + Data.ReferenceCategories, Entities.Category, + Cardinality.ZeroOrMore, + 11 + ) + .UpsertVia(session); + + ISealedEntitySchema? product = session.GetEntitySchema(Entities.Product); + Assert.NotNull(product); + + IAttributeSchema? productNameAttribute = product.GetAttribute(Data.AttributeName); + Assert.NotNull(productNameAttribute); + Assert.True(productNameAttribute.Localized); + } + ); + } + finally + { + _client!.DeleteCatalogIfExists(someCatalogName); + } + } + + [Fact] + public void ShouldAllowCreatingCatalogAndEntityCollectionsSchemas() + { + string someCatalogName = "differentCatalog"; + try + { + _client!.DefineCatalog(someCatalogName) + .WithDescription("This is a tutorial catalog.") + // define brand schema + .WithEntitySchema( + Entities.Brand, + whichIs => whichIs.WithDescription("A manufacturer of products.") + .WithAttribute( + Data.AttributeName, + thatIs => thatIs.Localized().Filterable().Sortable() + ) + ) + // define category schema + .WithEntitySchema( + Entities.Category, + whichIs => whichIs.WithDescription("A category of products.") + .WithAttribute( + Data.AttributeName, + thatIs => thatIs.Localized().Filterable().Sortable() + ) + .WithHierarchy() + ) + // define product schema + .WithEntitySchema( + Entities.Product, + whichIs => whichIs.WithDescription("A product in inventory.") + .WithAttribute( + Data.AttributeName, + thatIs => thatIs.Localized().Filterable().Sortable() + ) + .WithAttribute( + Data.AttributeCores, + thatIs => thatIs.WithDescription("Number of CPU cores.") + .Filterable() + ) + .WithAttribute( + Data.AttributeGraphics, + thatIs => thatIs.WithDescription("Graphics card.") + .Filterable() + ) + .WithPrice() + .WithReferenceToEntity( + Data.ReferenceBrand, Entities.Brand, Cardinality.ExactlyOne, + thatIs => thatIs.Indexed() + ) + .WithReferenceToEntity( + Data.ReferenceCategories, Entities.Category, Cardinality.ZeroOrMore, + thatIs => thatIs.Indexed() + ) + ) + // and now push all the definitions (mutations) to the server + .UpdateViaNewSession(_client); + Assert.Contains(someCatalogName, _client.GetCatalogNames()); + _client.QueryCatalog(someCatalogName, session => + { + ISet allEntityTypes = session.GetAllEntityTypes(); + Assert.Contains(Entities.Brand, allEntityTypes); + Assert.Contains(Entities.Product, allEntityTypes); + Assert.Contains(Entities.Category, allEntityTypes); + }); + } + finally + { + _client!.DeleteCatalogIfExists(someCatalogName); + } + } + + + + [Fact] + public void ShouldBeAbleToFetchNonCachedEntitySchemaFromCatalogSchema() + { + EvitaClient clientWithEmptyCache = new EvitaClient(_client!.Configuration); + clientWithEmptyCache.QueryCatalog( + Data.TestCatalog, + session => + { + IEntitySchema? productSchema = session.GetCatalogSchema().GetEntitySchema(Entities.Product); + Assert.NotNull(productSchema); + } + ); + } + + [Fact] + public void ShouldCreateCatalog() + { + string newCatalogName = "newCatalog"; + try + { + _client!.DefineCatalog(newCatalogName); + ISet catalogNames = _client.GetCatalogNames(); + + Assert.Equal(2 , catalogNames.Count); + Assert.Contains(Data.TestCatalog, catalogNames); + Assert.Contains(newCatalogName, catalogNames); + } + finally + { + _client!.DeleteCatalogIfExists(newCatalogName); + } + } + + [Fact] + public void ShouldRemoveCatalog() + { + string newCatalogName = "newCatalog"; + _client!.DefineCatalog(newCatalogName).UpdateViaNewSession(_client); + bool removed = _client.DeleteCatalogIfExists(newCatalogName); + Assert.True(removed); + + ISet catalogNames = _client.GetCatalogNames(); + Assert.Equal(1, catalogNames.Count); + Assert.Contains(Data.TestCatalog, catalogNames); + } + + [Fact] + public void ShouldReplaceCatalog() + { + string newCatalog = "newCatalog"; + _client!.DefineCatalog(newCatalog); + + ISet catalogNames = _client.GetCatalogNames(); + Assert.Equal(2, catalogNames.Count); + Assert.Contains(newCatalog, catalogNames); + Assert.Contains(Data.TestCatalog, catalogNames); + int initialSchemaVersion = _client.QueryCatalog(Data.TestCatalog, + evitaSessionContract => evitaSessionContract.GetCatalogSchema().Version); + + _client.ReplaceCatalog(Data.TestCatalog, newCatalog); + + ISet catalogNamesAgain = _client.GetCatalogNames(); + Assert.Equal(1, catalogNamesAgain.Count); + Assert.Contains(newCatalog, catalogNamesAgain); + Assert.Equal(initialSchemaVersion + 1, _client.QueryCatalog(newCatalog, + evitaSessionContract => evitaSessionContract.GetCatalogSchema().Version)); + } + + [Fact] + public void ShouldRenameCatalog() + { + string newCatalog = "newCatalog"; + + ISet catalogNames = _client!.GetCatalogNames(); + Assert.Equal(1, catalogNames.Count); + Assert.Contains(Data.TestCatalog, catalogNames); + int initialSchemaVersion = _client.QueryCatalog(Data.TestCatalog, + evitaSessionContract => evitaSessionContract.GetCatalogSchema().Version); + + _client.RenameCatalog(Data.TestCatalog, newCatalog); + + ISet catalogNamesAgain = _client.GetCatalogNames(); + Assert.Equal(1, catalogNamesAgain.Count); + Assert.Contains(newCatalog, catalogNamesAgain); + Assert.Equal(initialSchemaVersion + 1, _client.QueryCatalog(newCatalog, + evitaSessionContract => evitaSessionContract.GetCatalogSchema().Version)); + _ = _client.DeleteCatalogIfExists(newCatalog); + } + + [Fact] + public void ShouldReplaceCollection() + { + string newCollection = "newCollection"; + int? productCount = null; + int? productSchemaVersion = null; + _client!.UpdateCatalog( + Data.TestCatalog, + session => + { + Assert.Contains(Entities.Product, session.GetAllEntityTypes()); + Assert.DoesNotContain(newCollection, session.GetAllEntityTypes()); + session.DefineEntitySchema(newCollection) + .WithGlobalAttribute(Data.AttributeCode) + .UpdateVia(session); + Assert.Contains(newCollection, session.GetAllEntityTypes()); + productSchemaVersion = session.GetEntitySchemaOrThrow(Entities.Product).Version; + productCount = session.GetEntityCollectionSize(Entities.Product); + } + ); + _client.UpdateCatalog( + Data.TestCatalog, + session => session.ReplaceCollection( + newCollection, + Entities.Product + )); + _client.QueryCatalog( + Data.TestCatalog, + session => + { + Assert.DoesNotContain(Entities.Product, session.GetAllEntityTypes()); + Assert.Contains(newCollection, session.GetAllEntityTypes()); + Assert.Equal(productSchemaVersion!.Value + 1, + session.GetEntitySchemaOrThrow(newCollection).Version); + Assert.Equal(productCount!.Value, session.GetEntityCollectionSize(newCollection)); + } + ); + } + + [Fact] + public void ShouldRenameCollection() + { + string newCollection = "newCollection"; + int? productCount = null; + int? productSchemaVersion = null; + _client!.QueryCatalog( + Data.TestCatalog, + session => + { + Assert.Contains(Entities.Product, session.GetAllEntityTypes()); + Assert.DoesNotContain(newCollection, session.GetAllEntityTypes()); + productSchemaVersion = session.GetEntitySchemaOrThrow(Entities.Product).Version; + productCount = session.GetEntityCollectionSize(Entities.Product); + } + ); + _client.UpdateCatalog( + Data.TestCatalog, + session => session.RenameCollection( + Entities.Product, + newCollection + )); + _client.QueryCatalog( + Data.TestCatalog, + session => + { + Assert.DoesNotContain(Entities.Product, session.GetAllEntityTypes()); + Assert.Contains(newCollection, session.GetAllEntityTypes()); + Assert.Equal(productSchemaVersion!.Value + 1, + session.GetEntitySchemaOrThrow(newCollection).Version); + Assert.Equal(productCount!.Value, session.GetEntityCollectionSize(newCollection)); + } + ); + } + + [Fact] + public void ShouldCallTerminationCallbackWhenClientClosesSession() + { + Guid? terminatedSessionId = null; + EvitaClientSession theSession = _client!.CreateSession( + new SessionTraits( + Data.TestCatalog, + session => terminatedSessionId = session.SessionId + ) + ); + theSession.Close(); + Assert.NotNull(terminatedSessionId); + } + + [Fact] + public void ShouldCallTerminationCallbackWhenClientIsClosed() + { + Guid? terminatedSessionId = null; + _client!.CreateSession( + new SessionTraits( + Data.TestCatalog, + session => { ModifyGuid(ref terminatedSessionId, session.SessionId); } + ) + ); + _client.Close(); + Assert.NotNull(terminatedSessionId); + } + + [Fact] + public void ShouldTranslateErrorCorrectlyAndLeaveSessionOpen() + { + using EvitaClientSession clientSession = _client!.CreateReadOnlySession(Data.TestCatalog); + try + { + clientSession.GetEntity("nonExisting", 1, EntityFetchAll().Requirements!); + } + catch (EvitaInvalidUsageException ex) + { + Assert.True(clientSession.Active); + Assert.Equal("No collection found for entity type `nonExisting`!", ex.PublicMessage); + Assert.Equal(ex.PublicMessage, ex.PrivateMessage); + Assert.NotNull(ex.ErrorCode); + } + finally + { + clientSession.Close(); + } + } + + [Fact] + public void ShouldReturnEntitySchema() + { + EvitaClientSession evitaSession = _client!.CreateReadOnlySession(Data.TestCatalog); + Assert.NotNull(evitaSession.GetEntitySchema(Entities.Product)); + Assert.NotNull(evitaSession.GetEntitySchemaOrThrow(Entities.Product)); + } + + [Fact] + public void ShouldCreateAndDropEntityCollection() + { + _client!.UpdateCatalog( + Data.TestCatalog, + session => + { + string newEntityType = "newEntityType"; + session.DefineEntitySchema(newEntityType) + .WithAttribute(Data.AttributeName, thatIs => thatIs.Localized().Filterable()) + .UpdateVia(session); + + Assert.Contains(newEntityType, session.GetAllEntityTypes()); + session.DeleteCollection(newEntityType); + Assert.DoesNotContain(newEntityType, session.GetAllEntityTypes()); + } + ); + } + + [Fact] + public void ShouldUpsertNewEntity() + { + int? newProductId = null; + _client!.UpdateCatalog( + Data.TestCatalog, + session => + { + IEntityMutation entityMutation = DataManipulationUtil.CreateSomeNewProduct(session); + Assert.NotNull(entityMutation); + + EntityReference newProduct = session.UpsertEntity(entityMutation); + newProductId = newProduct.PrimaryKey; + } + ); + + _client.QueryCatalog( + Data.TestCatalog, + session => + { + ISealedEntity? loadedEntity = + session.GetEntity(Entities.Product, newProductId!.Value, EntityFetchAllContent()); + + Assert.NotNull(loadedEntity); + AssertSomeNewProductContent(loadedEntity); + } + ); + + // reset data + _client.UpdateCatalog( + Data.TestCatalog, + session => { session.DeleteEntity(Entities.Product, newProductId!.Value); } + ); + } + + [Fact] + public void ShouldUpsertAndFetchNewEntity() + { + int? newProductId = null; + _client!.UpdateCatalog( + Data.TestCatalog, + session => + { + IEntityMutation entityMutation = DataManipulationUtil.CreateSomeNewProduct(session); + + ISealedEntity updatedEntity = session.UpsertAndFetchEntity( + entityMutation, EntityFetchAll().Requirements! + ); + newProductId = updatedEntity.PrimaryKey; + + AssertSomeNewProductContent(updatedEntity); + } + ); + + // reset data + _client.UpdateCatalog( + Data.TestCatalog, + session => { session.DeleteEntity(Entities.Product, newProductId!.Value); } + ); + } + + [Fact] + public void ShouldDeleteExistingEntity() + { + int? newProductId = null; + _client!.UpdateCatalog( + Data.TestCatalog, + session => + { + IEntityMutation entityMutation = DataManipulationUtil.CreateSomeNewProduct(session); + ISealedEntity updatedEntity = session.UpsertAndFetchEntity( + entityMutation, EntityFetchAll().Requirements! + ); + newProductId = updatedEntity.PrimaryKey; + session.DeleteEntity(Entities.Product, updatedEntity.PrimaryKey!.Value); + } + ); + + _client.QueryCatalog( + Data.TestCatalog, + session => + { + ISealedEntity? loadedEntity = session.GetEntity( + Entities.Product, newProductId!.Value, EntityFetchAllContent() + ); + Assert.Null(loadedEntity); + } + ); + } + + [Fact] + public void ShouldDeleteAndFetchExistingEntity() + { + int? newProductId = null; + _client!.UpdateCatalog( + Data.TestCatalog, + session => + { + IEntityMutation entityMutation = DataManipulationUtil.CreateSomeNewProduct(session); + + ISealedEntity updatedEntity = session.UpsertAndFetchEntity( + entityMutation, EntityFetchAll().Requirements! + ); + newProductId = updatedEntity.PrimaryKey; + + ISealedEntity? removedEntity = session.DeleteEntity( + Entities.Product, updatedEntity.PrimaryKey!.Value, EntityFetchAllContent() + ); + + Assert.NotNull(removedEntity); + AssertSomeNewProductContent(removedEntity); + } + ); + + _client.QueryCatalog( + Data.TestCatalog, + session => + { + ISealedEntity? loadedEntity = session.GetEntity( + Entities.Product, newProductId!.Value, EntityFetchAllContent() + ); + Assert.Null(loadedEntity); + } + ); + } + + [Fact] + public void ShouldDeleteEntityByQuery() + { + int? newProductId = null; + _client!.UpdateCatalog( + Data.TestCatalog, + session => + { + IEntityMutation entityMutation = DataManipulationUtil.CreateSomeNewProduct(session); + + ISealedEntity updatedEntity = session.UpsertAndFetchEntity( + entityMutation, EntityFetchAll().Requirements! + ); + newProductId = updatedEntity.PrimaryKey; + + int deletedEntities = session.DeleteEntities( + Query( + Collection(Entities.Product), + FilterBy(EntityPrimaryKeyInSet(newProductId!.Value)) + ) + ); + + Assert.Equal(1, deletedEntities); + } + ); + + _client.QueryCatalog( + Data.TestCatalog, + session => + { + ISealedEntity? loadedEntity = session.GetEntity( + Entities.Product, newProductId!.Value, EntityFetchAllContent() + ); + Assert.Null(loadedEntity); + } + ); + } + + [Fact] + public void ShouldDeleteEntitiesAndFetchByQuery() + { + int? newProductId = null; + _client!.UpdateCatalog( + Data.TestCatalog, + session => + { + IEntityMutation entityMutation = DataManipulationUtil.CreateSomeNewProduct(session); + + ISealedEntity updatedEntity = session.UpsertAndFetchEntity( + entityMutation, EntityFetchAll().Requirements! + ); + newProductId = updatedEntity.PrimaryKey; + + ISealedEntity[] deletedEntities = session.DeleteSealedEntitiesAndReturnBodies( + Query( + Collection(Entities.Product), + FilterBy(EntityPrimaryKeyInSet(newProductId!.Value)), + Require(EntityFetchAll()) + ) + ); + + Assert.Single(deletedEntities); + AssertSomeNewProductContent(deletedEntities[0]); + } + ); + + _client.QueryCatalog( + Data.TestCatalog, + session => + { + ISealedEntity? loadedEntity = session.GetEntity( + Entities.Product, newProductId!.Value, EntityFetchAllContent() + ); + Assert.Null(loadedEntity); + } + ); + } + + [Fact] + public void ShouldDeleteHierarchy() + { + _client!.UpdateCatalog( + Data.TestCatalog, + session => + { + DataManipulationUtil.CreateSomeNewCategory(session, 50, null); + DataManipulationUtil.CreateSomeNewCategory(session, 51, 50); + DataManipulationUtil.CreateSomeNewCategory(session, 52, 51); + DataManipulationUtil.CreateSomeNewCategory(session, 53, 50); + + int deletedEntities = session.DeleteEntityAndItsHierarchy( + Entities.Category, 50 + ); + + Assert.Equal(4, deletedEntities); + } + ); + + _client.QueryCatalog( + Data.TestCatalog, + session => + { + Assert.Null(session.GetEntity(Entities.Category, 50, EntityFetchAllContent())); + Assert.Null(session.GetEntity(Entities.Category, 51, EntityFetchAllContent())); + Assert.Null(session.GetEntity(Entities.Category, 52, EntityFetchAllContent())); + Assert.Null(session.GetEntity(Entities.Category, 53, EntityFetchAllContent())); + } + ); + } + + [Fact] + public void ShouldDeleteHierarchyAndFetchRoot() + { + _client!.UpdateCatalog( + Data.TestCatalog, + session => + { + DataManipulationUtil.CreateSomeNewCategory(session, 50, null); + DataManipulationUtil.CreateSomeNewCategory(session, 51, 50); + DataManipulationUtil.CreateSomeNewCategory(session, 52, 51); + DataManipulationUtil.CreateSomeNewCategory(session, 53, 50); + + DeletedHierarchy deletedHierarchy = session.DeleteEntityAndItsHierarchy( + Entities.Category, 50, EntityFetchAllContent() + ); + + Assert.Equal(4, deletedHierarchy.DeletedEntities); + Assert.NotNull(deletedHierarchy.DeletedRootEntity); + Assert.Equal(50, deletedHierarchy.DeletedRootEntity!.PrimaryKey); + Assert.Equal("New category #50", + deletedHierarchy.DeletedRootEntity.GetAttribute(Data.AttributeName, Data.EnglishLocale)); + } + ); + + _client.QueryCatalog( + Data.TestCatalog, + session => + { + Assert.Null(session.GetEntity(Entities.Category, 50, EntityFetchAllContent())); + Assert.Null(session.GetEntity(Entities.Category, 51, EntityFetchAllContent())); + Assert.Null(session.GetEntity(Entities.Category, 52, EntityFetchAllContent())); + Assert.Null(session.GetEntity(Entities.Category, 53, EntityFetchAllContent())); + } + ); + } + + [Fact] + public void ShouldThrowWhenAddingEntityThatViolatesSchema() + { + Assert.Throws(() => DataManipulationUtil.CreateProductThatViolatesSchema(_client!, Entities.Product)); + } + + private static void AssertSomeNewProductContent(ISealedEntity loadedEntity) + { + Assert.NotNull(loadedEntity); + Assert.Equal("New product", loadedEntity.GetAttribute(Data.AttributeName, Data.EnglishLocale)); + } + + private static void ModifyGuid(ref Guid? guid, Guid newValue) + { + guid = newValue; + } +} \ No newline at end of file diff --git a/EvitaDB.TestX/EvitaDB.TestX.csproj b/EvitaDB.TestX/EvitaDB.TestX.csproj index 4a08fe2..6295f81 100644 --- a/EvitaDB.TestX/EvitaDB.TestX.csproj +++ b/EvitaDB.TestX/EvitaDB.TestX.csproj @@ -10,7 +10,7 @@ - + diff --git a/EvitaDB.TestX/SetupFixture.cs b/EvitaDB.TestX/SetupFixture.cs index 57aafb4..c5af0c1 100644 --- a/EvitaDB.TestX/SetupFixture.cs +++ b/EvitaDB.TestX/SetupFixture.cs @@ -30,7 +30,7 @@ public async Task GetClient() DataManipulationUtil.DeleteCreateAndSetupCatalog(evitaClient, Data.TestCatalog); return evitaClient; } - return await InitializeEvitaClient(); + return await InitializeEvitaContainerAndClientClient(); } public void ReturnClient(EvitaClient client) @@ -75,7 +75,7 @@ await client.Images.CreateImageAsync(new ImagesCreateParameters { FromImage = Im new Progress()); } - _ = await InitializeEvitaClient(true); + _ = await InitializeEvitaContainerAndClientClient(true); } public async Task DisposeAsync() @@ -87,31 +87,36 @@ public async Task DisposeAsync() } } - private async Task InitializeEvitaClient(bool cacheCreatedEntities = false) + private async Task InitializeEvitaContainerAndClientClient(bool cacheCreatedEntities = false) { - IContainer container = new ContainerBuilder() - .WithName($"evita-{Guid.NewGuid().ToString()}") - // Set the image for the container to "evitadb/evitadb". - .WithImage(ImageName) - // Bind ports of the container. - .WithPortBinding(GrpcPort, true) - .WithPortBinding(SystemApiPort, true) - .WithEnvironment("EVITA_JAVA_OPTS", "-Duser.timezone=UTC") - .WithWaitStrategy( - Wait.ForUnixContainer().UntilPortIsAvailable(GrpcPort).UntilPortIsAvailable(SystemApiPort)) - // Build the container configuration. - .Build(); - - // Start the container. - try + IContainer container; + using (var consumer = Consume.RedirectStdoutAndStderrToConsole()) { - await container.StartAsync() - .ConfigureAwait(false); - } - catch (Exception e) - { - Console.WriteLine(e); - throw; + container = new ContainerBuilder() + .WithName($"evita-{Guid.NewGuid().ToString()}") + // Set the image for the container to "evitadb/evitadb". + .WithImage(ImageName) + // Bind ports of the container. + .WithPortBinding(GrpcPort, true) + .WithPortBinding(SystemApiPort, true) + .WithEnvironment("EVITA_JAVA_OPTS", "-Duser.timezone=UTC") + .WithWaitStrategy( + Wait.ForUnixContainer().UntilPortIsAvailable(GrpcPort).UntilPortIsAvailable(SystemApiPort)) + .WithOutputConsumer(consumer) + // Build the container configuration. + .Build(); + + // Start the container. + try + { + await container.StartAsync() + .ConfigureAwait(false); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } } // create a evita client configuration the the running instance of evita server @@ -131,7 +136,6 @@ await container.StartAsync() } _testSuites.Add(new EvitaTestSuite(evitaClient, container)); - _clients.Enqueue(evitaClient); return evitaClient; } diff --git a/EvitaDB.TestX/Utils/DataManipulationUtil.cs b/EvitaDB.TestX/Utils/DataManipulationUtil.cs index 25b2e0b..21fb087 100644 --- a/EvitaDB.TestX/Utils/DataManipulationUtil.cs +++ b/EvitaDB.TestX/Utils/DataManipulationUtil.cs @@ -106,7 +106,7 @@ private static IEntitySchema CreateProductSchema(EvitaClientSession session, str return schema; } - public static IList CreateProductsThatMatchSchema(EvitaClientSession session, string entityType, int count) + private static IList CreateProductsThatMatchSchema(EvitaClientSession session, string entityType, int count) { List entities = new List(); @@ -172,7 +172,7 @@ public static IList CreateProductsThatMatchSchema(EvitaClientSess entityReference.Value.PrimaryKey!.Value, EntityFetchAllContent()); Assert.NotNull(entity); - Assert.Equal(enAttributeName, entity!.GetAttribute(Data.AttributeName, Data.EnglishLocale)); + Assert.Equal(enAttributeName, entity.GetAttribute(Data.AttributeName, Data.EnglishLocale)); Assert.Equal(csAttributeName, entity.GetAttribute(Data.AttributeName, Data.CzechLocale)); Assert.Equal(attributeCode, entity.GetAttribute(Data.AttributeCode)); Assert.Equal(quantity, entity.GetAttribute(Data.AttributeQuantity)); @@ -200,7 +200,7 @@ public static void CreateProductThatViolatesSchema(EvitaClient client, string en builder.UpsertVia(rwSession); } - public static ISealedEntity? CreateSomeNewCategory(EvitaClientSession session, int primaryKey, int? parentPrimaryKey = null) + public static ISealedEntity? CreateSomeNewCategory(EvitaClientSession session, int primaryKey, int? parentPrimaryKey) { IEntityBuilder builder = session.CreateNewEntity(Entities.Category, primaryKey) .SetAttribute(Data.AttributeName, Data.EnglishLocale, "New category #" + primaryKey) @@ -221,7 +221,7 @@ public static void CreateProductThatViolatesSchema(EvitaClient client, string en return session.GetEntity(Entities.Category, primaryKey, EntityFetchAllContent()); } - private static IEntityMutation CreateSomeNewProduct(EvitaClientSession session) + public static IEntityMutation CreateSomeNewProduct(EvitaClientSession session) { return session.CreateNewEntity(Entities.Product) .SetAttribute(Data.AttributeName, Data.EnglishLocale, "New product") @@ -250,7 +250,7 @@ public static IDictionary> DeleteCreateAndSetupCata if (!allEntityTypes.Contains(Entities.Category) || session.GetEntityCollectionSize(Entities.Category) == 0) { - ISealedEntity category1 = CreateSomeNewCategory(session, 1)!; + ISealedEntity category1 = CreateSomeNewCategory(session, 1, null)!; ISealedEntity category2 = CreateSomeNewCategory(session, 2, 1)!; createdEntities.Add(Entities.Category, new List { category1, category2 }); }