diff --git a/.gitignore b/.gitignore index 6c8a8efaa13d..fe14c1529238 100644 --- a/.gitignore +++ b/.gitignore @@ -415,6 +415,9 @@ FodyWeavers.xsd *.iml *.iws +# VS Code +.vscode/ + .env certs/ launchSettings.json diff --git a/dotnet/src/VectorData/CosmosNoSql/CosmosNoSqlCollection.cs b/dotnet/src/VectorData/CosmosNoSql/CosmosNoSqlCollection.cs index 678eb0e8dd8b..1dbf66eca099 100644 --- a/dotnet/src/VectorData/CosmosNoSql/CosmosNoSqlCollection.cs +++ b/dotnet/src/VectorData/CosmosNoSql/CosmosNoSqlCollection.cs @@ -322,6 +322,8 @@ await this._database /// public override async Task GetAsync(TKey key, RecordRetrievalOptions? options = null, CancellationToken cancellationToken = default) { + Verify.NotNull(key); + return await this.GetAsync([key], options, cancellationToken) .FirstOrDefaultAsync(cancellationToken) .ConfigureAwait(false); @@ -343,11 +345,17 @@ public override async IAsyncEnumerable GetAsync( throw new NotSupportedException(VectorDataStrings.IncludeVectorsNotSupportedWithEmbeddingGeneration); } + var compositeKeys = GetCompositeKeys(keys).ToList(); + if (compositeKeys.Count == 0) + { + yield break; + } + var queryDefinition = CosmosNoSqlCollectionQueryBuilder.BuildSelectQuery( this._model, this._model.KeyProperty.StorageName, this._partitionKeyProperty.StorageName, - GetCompositeKeys(keys).ToList(), + compositeKeys, includeVectors); await foreach (var jsonObject in this.GetItemsAsync(queryDefinition, OperationName, cancellationToken).ConfigureAwait(false)) diff --git a/dotnet/src/VectorData/Redis/RedisJsonCollection.cs b/dotnet/src/VectorData/Redis/RedisJsonCollection.cs index 91b4c1998610..6db5dbf92e9e 100644 --- a/dotnet/src/VectorData/Redis/RedisJsonCollection.cs +++ b/dotnet/src/VectorData/Redis/RedisJsonCollection.cs @@ -289,6 +289,11 @@ public override async IAsyncEnumerable GetAsync(IEnumerable keys, }; #pragma warning restore CA1851 // Possible multiple enumerations of 'IEnumerable' collection + if (keysList.Count == 0) + { + yield break; + } + // Create Options var maybePrefixedKeys = keysList.Select(key => this.PrefixKeyIfNeeded(key)); var redisKeys = maybePrefixedKeys.Select(x => new RedisKey(x)).ToArray(); @@ -392,6 +397,11 @@ public override async Task UpsertAsync(IEnumerable records, Cancellatio redisRecords.Add((maybePrefixedKey, redisJsonRecord.Key, redisJsonRecord.SerializedRecord)); } + if (redisRecords.Count == 0) + { + return; + } + // Upsert. var keyPathValues = redisRecords.Select(x => new KeyPathValue(x.maybePrefixedKey, "$", x.serializedRecord)).ToArray(); await this.RunOperationAsync( diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/AzureAISearchAllSupportedTypesTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/AzureAISearchAllSupportedTypesTests.cs new file mode 100644 index 000000000000..a69879faa3c5 --- /dev/null +++ b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/AzureAISearchAllSupportedTypesTests.cs @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft. All rights reserved. + +using AzureAISearch.ConformanceTests.Support; +using Microsoft.Extensions.VectorData; +using VectorData.ConformanceTests.Xunit; +using Xunit; + +namespace AzureAISearch.ConformanceTests; + +public class AzureAISearchAllSupportedTypesTests(AzureAISearchFixture fixture) : IClassFixture +{ + [ConditionalFact] + public async Task AllTypesBatchGetAsync() + { + var collection = fixture.TestStore.DefaultVectorStore.GetCollection("all-types", AzureAISearchAllTypes.GetRecordDefinition()); + await collection.EnsureCollectionExistsAsync(); + + List records = + [ + new() + { + Id = "all-types-1", + BoolProperty = true, + NullableBoolProperty = false, + StringProperty = "string prop 1", + NullableStringProperty = "nullable prop 1", + IntProperty = 1, + NullableIntProperty = 10, + LongProperty = 100L, + NullableLongProperty = 1000L, + FloatProperty = 10.5f, + NullableFloatProperty = 100.5f, + DoubleProperty = 23.75d, + NullableDoubleProperty = 233.75d, + DateTimeOffsetProperty = DateTimeOffset.UtcNow, + NullableDateTimeOffsetProperty = DateTimeOffset.UtcNow, + StringArray = ["one", "two"], + StringList = ["eleven", "twelve"], + BoolArray = [true, false], + BoolList = [true, false], + IntArray = [1, 2], + IntList = [11, 12], + LongArray = [100L, 200L], + LongList = [1100L, 1200L], + FloatArray = [1.5f, 2.5f], + FloatList = [11.5f, 12.5f], + DoubleArray = [1.5d, 2.5d], + DoubleList = [11.5d, 12.5d], + DateTimeOffsetArray = [DateTimeOffset.UtcNow, DateTimeOffset.UtcNow], + DateTimeOffsetList = [DateTimeOffset.UtcNow, DateTimeOffset.UtcNow], + Embedding = new ReadOnlyMemory([1.5f, 2.5f, 3.5f, 4.5f, 5.5f, 6.5f, 7.5f, 8.5f]) + }, + new() + { + Id = "all-types-2", + BoolProperty = false, + NullableBoolProperty = null, + StringProperty = "string prop 2", + NullableStringProperty = null, + IntProperty = 2, + NullableIntProperty = null, + LongProperty = 200L, + NullableLongProperty = null, + FloatProperty = 20.5f, + NullableFloatProperty = null, + DoubleProperty = 43.75, + NullableDoubleProperty = null, + Embedding = ReadOnlyMemory.Empty, + // From https://learn.microsoft.com/en-us/rest/api/searchservice/supported-data-types: + // "All of the above types are nullable, except for collections of primitive and complex types, for example, Collection(Edm.String)" + // So for collections, we can't use nulls. + StringArray = [], + StringList = [], + BoolArray = [], + BoolList = [], + IntArray = [], + IntList = [], + LongArray = [], + LongList = [], + FloatArray = [], + FloatList = [], + DoubleArray = [], + DoubleList = [], + DateTimeOffsetArray = [], + DateTimeOffsetList = [], + } + ]; + + try + { + await collection.UpsertAsync(records); + + var allTypes = await collection.GetAsync(records.Select(r => r.Id), new RecordRetrievalOptions { IncludeVectors = true }).ToListAsync(); + + var allTypes1 = allTypes.Single(x => x.Id == records[0].Id); + var allTypes2 = allTypes.Single(x => x.Id == records[1].Id); + + records[0].AssertEqual(allTypes1); + records[1].AssertEqual(allTypes2); + } + finally + { + await collection.EnsureCollectionDeletedAsync(); + } + } +} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/AzureAISearchCollectionManagementTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/AzureAISearchCollectionManagementTests.cs new file mode 100644 index 000000000000..b2b6fb7605eb --- /dev/null +++ b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/AzureAISearchCollectionManagementTests.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft. All rights reserved. + +using AzureAISearch.ConformanceTests.Support; +using VectorData.ConformanceTests; +using Xunit; + +namespace AzureAISearch.ConformanceTests; + +public class AzureAISearchCollectionManagementTests(AzureAISearchFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ + // Azure AI search only supports lowercase letters, digits or dashes. + public override string CollectionName => "collection-tests"; +} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Filter/AzureAISearchBasicFilterTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/AzureAISearchFilterTests.cs similarity index 66% rename from dotnet/test/VectorData/AzureAISearch.ConformanceTests/Filter/AzureAISearchBasicFilterTests.cs rename to dotnet/test/VectorData/AzureAISearch.ConformanceTests/AzureAISearchFilterTests.cs index 3aed091e4d3d..206bb7cb41bb 100644 --- a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Filter/AzureAISearchBasicFilterTests.cs +++ b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/AzureAISearchFilterTests.cs @@ -1,20 +1,20 @@ // Copyright (c) Microsoft. All rights reserved. using AzureAISearch.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; +using VectorData.ConformanceTests; using VectorData.ConformanceTests.Support; using Xunit; -namespace AzureAISearch.ConformanceTests.Filter; +namespace AzureAISearch.ConformanceTests; -public class AzureAISearchBasicFilterTests(AzureAISearchBasicFilterTests.Fixture fixture) - : BasicFilterTests(fixture), IClassFixture +public class AzureAISearchFilterTests(AzureAISearchFilterTests.Fixture fixture) + : FilterTests(fixture), IClassFixture { // Azure AI Search only supports search.in() over strings public override Task Contains_over_inline_int_array() => Assert.ThrowsAsync(() => base.Contains_over_inline_int_array()); - public new class Fixture : BasicFilterTests.Fixture + public new class Fixture : FilterTests.Fixture { public override TestStore TestStore => AzureAISearchTestStore.Instance; diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchBatchConformanceTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchBatchConformanceTests.cs deleted file mode 100644 index 023336d44d78..000000000000 --- a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchBatchConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using AzureAISearch.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace AzureAISearch.ConformanceTests.CRUD; - -public class AzureAISearchBatchConformanceTests(AzureAISearchSimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchDynamicDataModelConformanceTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchDynamicDataModelConformanceTests.cs deleted file mode 100644 index 3c753339e833..000000000000 --- a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchDynamicDataModelConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using AzureAISearch.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace AzureAISearch.ConformanceTests.CRUD; - -public class AzureAISearchDynamicDataModelConformanceTests(AzureAISearchDynamicDataModelFixture fixture) - : DynamicDataModelConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchNoDataConformanceTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchNoDataConformanceTests.cs deleted file mode 100644 index 48259b4d3270..000000000000 --- a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchNoDataConformanceTests.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using AzureAISearch.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace AzureAISearch.ConformanceTests.CRUD; - -public class AzureAISearchNoDataConformanceTests(AzureAISearchNoDataConformanceTests.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoDataConformanceTests.Fixture - { - public override string CollectionName => "nodata-" + AzureAISearchTestEnvironment.TestIndexPostfix; - - public override TestStore TestStore => AzureAISearchTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchNoVectorConformanceTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchNoVectorConformanceTests.cs deleted file mode 100644 index c69223545fdb..000000000000 --- a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchNoVectorConformanceTests.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using AzureAISearch.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace AzureAISearch.ConformanceTests.CRUD; - -public class AzureAISearchNoVectorConformanceTests(AzureAISearchNoVectorConformanceTests.Fixture fixture) - : NoVectorConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoVectorConformanceTests.Fixture - { - public override string CollectionName => "novector-" + AzureAISearchTestEnvironment.TestIndexPostfix; - - public override TestStore TestStore => AzureAISearchTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchRecordConformanceTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchRecordConformanceTests.cs deleted file mode 100644 index d68c20da2618..000000000000 --- a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchRecordConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using AzureAISearch.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace AzureAISearch.ConformanceTests.CRUD; - -public class AzureAISearchRecordConformanceTests(AzureAISearchSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Collections/AzureAISearchCollectionConformanceTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Collections/AzureAISearchCollectionConformanceTests.cs deleted file mode 100644 index cc06d28533f7..000000000000 --- a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Collections/AzureAISearchCollectionConformanceTests.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using AzureAISearch.ConformanceTests.Support; -using VectorData.ConformanceTests.Collections; -using Xunit; - -namespace AzureAISearch.ConformanceTests.Collections; - -public class AzureAISearchCollectionConformanceTests(AzureAISearchFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ - // Azure AI search only supports lowercase letters, digits or dashes. - public override string CollectionName => "collection-tests"; -} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Filter/AzureAISearchBasicQueryTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Filter/AzureAISearchBasicQueryTests.cs deleted file mode 100644 index 6ef3288fca13..000000000000 --- a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Filter/AzureAISearchBasicQueryTests.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using AzureAISearch.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace AzureAISearch.ConformanceTests.Filter; - -public class AzureAISearchBasicQueryTests(AzureAISearchBasicQueryTests.Fixture fixture) - : BasicQueryTests(fixture), IClassFixture -{ - // Azure AI Search only supports search.in() over strings - public override Task Contains_over_inline_int_array() - => Assert.ThrowsAsync(() => base.Contains_over_inline_int_array()); - - public new class Fixture : BasicQueryTests.QueryFixture - { - public override TestStore TestStore => AzureAISearchTestStore.Instance; - - // Azure AI search only supports lowercase letters, digits or dashes. - public override string CollectionName => "query-tests" + AzureAISearchTestEnvironment.TestIndexPostfix; - } -} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchAllSupportedTypesTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchAllSupportedTypesTests.cs similarity index 100% rename from dotnet/test/VectorData/AzureAISearch.ConformanceTests/CRUD/AzureAISearchAllSupportedTypesTests.cs rename to dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchAllSupportedTypesTests.cs diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchBasicModelTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchBasicModelTests.cs new file mode 100644 index 000000000000..772d2cb40047 --- /dev/null +++ b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchBasicModelTests.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft. All rights reserved. + +using AzureAISearch.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace AzureAISearch.ConformanceTests.ModelTests; + +public class AzureAISearchBasicModelTests(AzureAISearchBasicModelTests.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public new class Fixture : BasicModelTests.Fixture + { + public override string CollectionName => "basic-" + AzureAISearchTestEnvironment.TestIndexPostfix; + + public override TestStore TestStore => AzureAISearchTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchDynamicModelTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchDynamicModelTests.cs new file mode 100644 index 000000000000..e89ab37442d6 --- /dev/null +++ b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchDynamicModelTests.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft. All rights reserved. + +using AzureAISearch.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace AzureAISearch.ConformanceTests.ModelTests; + +public class AzureAISearchDynamicModelTests(AzureAISearchDynamicModelTests.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public new class Fixture : DynamicModelTests.Fixture + { + public override string CollectionName => "dynamic-" + AzureAISearchTestEnvironment.TestIndexPostfix; + + public override TestStore TestStore => AzureAISearchTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchNoDataModelTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchNoDataModelTests.cs new file mode 100644 index 000000000000..87b0acac8939 --- /dev/null +++ b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchNoDataModelTests.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft. All rights reserved. + +using AzureAISearch.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace AzureAISearch.ConformanceTests.ModelTests; + +public class AzureAISearchNoDataModelTests(AzureAISearchNoDataModelTests.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public new class Fixture : NoDataModelTests.Fixture + { + public override string CollectionName => "nodata-" + AzureAISearchTestEnvironment.TestIndexPostfix; + + public override TestStore TestStore => AzureAISearchTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchNoVectorModelTests.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchNoVectorModelTests.cs new file mode 100644 index 000000000000..d61c2ddfac37 --- /dev/null +++ b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/ModelTests/AzureAISearchNoVectorModelTests.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft. All rights reserved. + +using AzureAISearch.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace AzureAISearch.ConformanceTests.ModelTests; + +public class AzureAISearchNoVectorModelTests(AzureAISearchNoVectorModelTests.Fixture fixture) + : NoVectorModelTests(fixture), IClassFixture +{ + public new class Fixture : NoVectorModelTests.Fixture + { + public override string CollectionName => "novector-" + AzureAISearchTestEnvironment.TestIndexPostfix; + + public override TestStore TestStore => AzureAISearchTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Support/AzureAISearchDynamicDataModelFixture.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Support/AzureAISearchDynamicDataModelFixture.cs deleted file mode 100644 index b3494c0dc0a0..000000000000 --- a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Support/AzureAISearchDynamicDataModelFixture.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace AzureAISearch.ConformanceTests.Support; - -public class AzureAISearchDynamicDataModelFixture : DynamicDataModelFixture -{ - public override string CollectionName => "dynamicdatamodel-" + AzureAISearchTestEnvironment.TestIndexPostfix; - - public override TestStore TestStore => AzureAISearchTestStore.Instance; -} diff --git a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Support/AzureAISearchSimpleModelFixture.cs b/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Support/AzureAISearchSimpleModelFixture.cs deleted file mode 100644 index 510d537e4cec..000000000000 --- a/dotnet/test/VectorData/AzureAISearch.ConformanceTests/Support/AzureAISearchSimpleModelFixture.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace AzureAISearch.ConformanceTests.Support; - -public class AzureAISearchSimpleModelFixture : SimpleModelFixture -{ - public override string CollectionName => "simplemodel-" + AzureAISearchTestEnvironment.TestIndexPostfix; - - public override TestStore TestStore => AzureAISearchTestStore.Instance; -} diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CRUD/CosmosMongoBatchConformanceTests.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CRUD/CosmosMongoBatchConformanceTests.cs deleted file mode 100644 index 802f7be230a0..000000000000 --- a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CRUD/CosmosMongoBatchConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using CosmosMongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace CosmosMongoDB.ConformanceTests.CRUD; - -public class CosmosMongoBatchConformanceTests(CosmosMongoSimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CRUD/CosmosMongoNoDataConformanceTests.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CRUD/CosmosMongoNoDataConformanceTests.cs deleted file mode 100644 index bd4b2fecdc38..000000000000 --- a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CRUD/CosmosMongoNoDataConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using CosmosMongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace CosmosMongoDB.ConformanceTests.CRUD; - -public class CosmosMongoNoDataConformanceTests(CosmosMongoNoDataConformanceTests.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoDataConformanceTests.Fixture - { - public override TestStore TestStore => CosmosMongoTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CRUD/CosmosMongoNoVectorConformanceTests.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CRUD/CosmosMongoNoVectorConformanceTests.cs deleted file mode 100644 index 68fd4f28a1e4..000000000000 --- a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CRUD/CosmosMongoNoVectorConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using CosmosMongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace CosmosMongoDB.ConformanceTests.CRUD; - -public class CosmosMongoNoVectorConformanceTests(CosmosMongoNoVectorConformanceTests.Fixture fixture) - : NoVectorConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoVectorConformanceTests.Fixture - { - public override TestStore TestStore => CosmosMongoTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CRUD/CosmosMongoRecordConformanceTests.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CRUD/CosmosMongoRecordConformanceTests.cs deleted file mode 100644 index 45a5e52db360..000000000000 --- a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CRUD/CosmosMongoRecordConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using CosmosMongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace CosmosMongoDB.ConformanceTests.CRUD; - -public class CosmosMongoRecordConformanceTests(CosmosMongoSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/Collections/CosmosMongoCollectionConformanceTests.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/Collections/CosmosMongoCollectionConformanceTests.cs deleted file mode 100644 index 50276278328c..000000000000 --- a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/Collections/CosmosMongoCollectionConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using CosmosMongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.Collections; -using Xunit; - -namespace CosmosMongoDB.ConformanceTests.Collections; - -public class CosmosMongoCollectionConformanceTests(CosmosMongoFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CosmosMongoCollectionManagementTests.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CosmosMongoCollectionManagementTests.cs new file mode 100644 index 000000000000..ea8f6ff1582a --- /dev/null +++ b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CosmosMongoCollectionManagementTests.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. + +using CosmosMongoDB.ConformanceTests.Support; +using VectorData.ConformanceTests; +using Xunit; + +namespace CosmosMongoDB.ConformanceTests; + +public class CosmosMongoCollectionManagementTests(CosmosMongoFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/Filter/CosmosMongoBasicFilterTests.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CosmosMongoFilterTests.cs similarity index 89% rename from dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/Filter/CosmosMongoBasicFilterTests.cs rename to dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CosmosMongoFilterTests.cs index 80c263453e80..520f79ba0d0b 100644 --- a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/Filter/CosmosMongoBasicFilterTests.cs +++ b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CosmosMongoFilterTests.cs @@ -1,15 +1,15 @@ // Copyright (c) Microsoft. All rights reserved. using CosmosMongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; +using VectorData.ConformanceTests; using VectorData.ConformanceTests.Support; using VectorData.ConformanceTests.Xunit; using Xunit; -namespace CosmosMongoDB.ConformanceTests.Filter; +namespace CosmosMongoDB.ConformanceTests; -public class CosmosMongoBasicFilterTests(CosmosMongoBasicFilterTests.Fixture fixture) - : BasicFilterTests(fixture), IClassFixture +public class CosmosMongoFilterTests(CosmosMongoFilterTests.Fixture fixture) + : FilterTests(fixture), IClassFixture { // Specialized MongoDB syntax for NOT over Contains ($nin) [ConditionalFact] @@ -65,7 +65,7 @@ public override Task Legacy_AnyTagEqualTo_array() public override Task Legacy_AnyTagEqualTo_List() => Assert.ThrowsAsync(() => base.Legacy_AnyTagEqualTo_List()); - public new class Fixture : BasicFilterTests.Fixture + public new class Fixture : FilterTests.Fixture { public override TestStore TestStore => CosmosMongoTestStore.Instance; diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CosmosMongoTestSuiteImplementationTests.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CosmosMongoTestSuiteImplementationTests.cs index 97ca7d89ee89..086512e47bd2 100644 --- a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CosmosMongoTestSuiteImplementationTests.cs +++ b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/CosmosMongoTestSuiteImplementationTests.cs @@ -1,8 +1,8 @@ // Copyright (c) Microsoft. All rights reserved. using VectorData.ConformanceTests; -using VectorData.ConformanceTests.CRUD; using VectorData.ConformanceTests.HybridSearch; +using VectorData.ConformanceTests.ModelTests; using VectorData.ConformanceTests.VectorSearch; namespace CosmosMongoDB.ConformanceTests; @@ -13,7 +13,7 @@ public class CosmosMongoTestSuiteImplementationTests : TestSuiteImplementationTe [ typeof(VectorSearchDistanceFunctionComplianceTests<>), typeof(VectorSearchWithFilterConformanceTests<>), - typeof(DynamicDataModelConformanceTests<>), + typeof(DynamicModelTests<>), // Hybrid search not supported typeof(KeywordVectorizedHybridSearchComplianceTests<>), diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/Filter/CosmosMongoBasicQueryTests.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/Filter/CosmosMongoBasicQueryTests.cs deleted file mode 100644 index 01fcff7552cf..000000000000 --- a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/Filter/CosmosMongoBasicQueryTests.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using CosmosMongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using VectorData.ConformanceTests.Xunit; -using Xunit; - -namespace CosmosMongoDB.ConformanceTests.Filter; - -public class CosmosMongoBasicQueryTests(CosmosMongoBasicQueryTests.Fixture fixture) - : BasicQueryTests(fixture), IClassFixture -{ - // Specialized MongoDB syntax for NOT over Contains ($nin) - [ConditionalFact] - public virtual Task Not_over_Contains() - => this.TestFilterAsync( - r => !new[] { 8, 10 }.Contains(r.Int), - r => !new[] { 8, 10 }.Contains((int)r["Int"]!)); - - // MongoDB currently doesn't support null checking ({ "Foo" : null }) in vector search pre-filters - public override Task Equal_with_null_reference_type() - => Assert.ThrowsAsync(() => base.Equal_with_null_reference_type()); - - public override Task Equal_with_null_captured() - => Assert.ThrowsAsync(() => base.Equal_with_null_captured()); - - public override Task NotEqual_with_null_reference_type() - => Assert.ThrowsAsync(() => base.NotEqual_with_null_reference_type()); - - public override Task NotEqual_with_null_captured() - => Assert.ThrowsAsync(() => base.NotEqual_with_null_captured()); - - public override Task Equal_int_property_with_null_nullable_int() - => Assert.ThrowsAsync(() => base.Equal_int_property_with_null_nullable_int()); - - // MongoDB currently doesn't support NOT in vector search pre-filters - // (https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/#atlas-vector-search-pre-filter) - public override Task Not_over_And() - => Assert.ThrowsAsync(() => base.Not_over_And()); - - public override Task Not_over_Or() - => Assert.ThrowsAsync(() => base.Not_over_Or()); - - public override Task Contains_over_field_string_array() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_array()); - - public override Task Contains_over_field_string_List() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_List()); - - public new class Fixture : BasicQueryTests.QueryFixture - { - public override TestStore TestStore => CosmosMongoTestStore.Instance; - - protected override string IndexKind => Microsoft.Extensions.VectorData.IndexKind.IvfFlat; - protected override string DistanceFunction => Microsoft.Extensions.VectorData.DistanceFunction.CosineDistance; - } -} diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/ModelTests/CosmosMongoBasicModelTests.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/ModelTests/CosmosMongoBasicModelTests.cs new file mode 100644 index 000000000000..0ea82a0a8cc8 --- /dev/null +++ b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/ModelTests/CosmosMongoBasicModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using CosmosMongoDB.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace CosmosMongoDB.ConformanceTests.ModelTests; + +public class CosmosMongoBasicModelTests(CosmosMongoBasicModelTests.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => CosmosMongoTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/ModelTests/CosmosMongoNoDataModelTests.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/ModelTests/CosmosMongoNoDataModelTests.cs new file mode 100644 index 000000000000..9e486c7717ee --- /dev/null +++ b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/ModelTests/CosmosMongoNoDataModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using CosmosMongoDB.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace CosmosMongoDB.ConformanceTests.ModelTests; + +public class CosmosMongoNoDataModelTests(CosmosMongoNoDataModelTests.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public new class Fixture : NoDataModelTests.Fixture + { + public override TestStore TestStore => CosmosMongoTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/ModelTests/CosmosMongoNoVectorModelTests.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/ModelTests/CosmosMongoNoVectorModelTests.cs new file mode 100644 index 000000000000..1736512c9802 --- /dev/null +++ b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/ModelTests/CosmosMongoNoVectorModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using CosmosMongoDB.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace CosmosMongoDB.ConformanceTests.ModelTests; + +public class CosmosMongoNoVectorModelTests(CosmosMongoNoVectorModelTests.Fixture fixture) + : NoVectorModelTests(fixture), IClassFixture +{ + public new class Fixture : NoVectorModelTests.Fixture + { + public override TestStore TestStore => CosmosMongoTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/Support/CosmosMongoSimpleModelFixture.cs b/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/Support/CosmosMongoSimpleModelFixture.cs deleted file mode 100644 index 426528b78f3c..000000000000 --- a/dotnet/test/VectorData/CosmosMongoDB.ConformanceTests/Support/CosmosMongoSimpleModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace CosmosMongoDB.ConformanceTests.Support; - -public class CosmosMongoSimpleModelFixture : SimpleModelFixture -{ - public override TestStore TestStore => CosmosMongoTestStore.Instance; -} diff --git a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CRUD/CosmosNoSqlNoDataConformanceTests.cs b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CRUD/CosmosNoSqlNoDataConformanceTests.cs deleted file mode 100644 index 277acb33f7c8..000000000000 --- a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CRUD/CosmosNoSqlNoDataConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using CosmosNoSql.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace CosmosNoSql.ConformanceTests.CRUD; - -public class CosmosNoSqlNoDataConformanceTests(CosmosNoSqlNoDataConformanceTests.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoDataConformanceTests.Fixture - { - public override TestStore TestStore => CosmosNoSqlTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CRUD/CosmosNoSqlNoVectorConformanceTests.cs b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CRUD/CosmosNoSqlNoVectorConformanceTests.cs deleted file mode 100644 index 65ed7d73ae58..000000000000 --- a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CRUD/CosmosNoSqlNoVectorConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using CosmosNoSql.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace CosmosNoSql.ConformanceTests.CRUD; - -public class CosmosNoSqlNoVectorConformanceTests(CosmosNoSqlNoVectorConformanceTests.Fixture fixture) - : NoVectorConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoVectorConformanceTests.Fixture - { - public override TestStore TestStore => CosmosNoSqlTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/Collections/CosmosNoSqlCollectionConformanceTests.cs b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/Collections/CosmosNoSqlCollectionConformanceTests.cs deleted file mode 100644 index 2985553f3708..000000000000 --- a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/Collections/CosmosNoSqlCollectionConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using CosmosNoSql.ConformanceTests.Support; -using VectorData.ConformanceTests.Collections; -using Xunit; - -namespace CosmosNoSql.ConformanceTests.Collections; - -public class CosmosNoSqlCollectionConformanceTests(CosmosNoSqlFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CosmosNoSqlCollectionManagementTests.cs b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CosmosNoSqlCollectionManagementTests.cs new file mode 100644 index 000000000000..1d59fe378e75 --- /dev/null +++ b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CosmosNoSqlCollectionManagementTests.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. + +using CosmosNoSql.ConformanceTests.Support; +using VectorData.ConformanceTests; +using Xunit; + +namespace CosmosNoSql.ConformanceTests; + +public class CosmosNoSqlCollectionManagementTests(CosmosNoSqlFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} diff --git a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CosmosNoSqlFilterTests.cs b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CosmosNoSqlFilterTests.cs new file mode 100644 index 000000000000..62665e1acc99 --- /dev/null +++ b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CosmosNoSqlFilterTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using CosmosNoSql.ConformanceTests.Support; +using VectorData.ConformanceTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace CosmosNoSql.ConformanceTests; + +public class CosmosNoSqlFilterTests(CosmosNoSqlFilterTests.Fixture fixture) + : FilterTests(fixture), IClassFixture +{ + public new class Fixture : FilterTests.Fixture + { + public override TestStore TestStore => CosmosNoSqlTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CosmosNoSqlTestSuiteImplementationTests.cs b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CosmosNoSqlTestSuiteImplementationTests.cs index fd0819e9a66f..94b2b8b65bb1 100644 --- a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CosmosNoSqlTestSuiteImplementationTests.cs +++ b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/CosmosNoSqlTestSuiteImplementationTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. using VectorData.ConformanceTests; -using VectorData.ConformanceTests.CRUD; using VectorData.ConformanceTests.VectorSearch; namespace CosmosNoSql.ConformanceTests; @@ -11,8 +10,6 @@ public class CosmosNoSqlTestSuiteImplementationTests : TestSuiteImplementationTe protected override ICollection IgnoredTestBases { get; } = [ typeof(VectorSearchDistanceFunctionComplianceTests<>), - typeof(VectorSearchWithFilterConformanceTests<>), - typeof(DynamicDataModelConformanceTests<>), - typeof(BatchConformanceTests<>) + typeof(VectorSearchWithFilterConformanceTests<>) ]; } diff --git a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/Filter/CosmosNoSqlBasicFilterTests.cs b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/Filter/CosmosNoSqlBasicFilterTests.cs deleted file mode 100644 index 62a4dee7e83c..000000000000 --- a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/Filter/CosmosNoSqlBasicFilterTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using CosmosNoSql.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace CosmosNoSql.ConformanceTests.Filter; - -public class CosmosNoSqlBasicFilterTests(CosmosNoSqlBasicFilterTests.Fixture fixture) - : BasicFilterTests(fixture), IClassFixture -{ - public new class Fixture : BasicFilterTests.Fixture - { - public override TestStore TestStore => CosmosNoSqlTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/Filter/CosmosNoSqlBasicQueryTests.cs b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/Filter/CosmosNoSqlBasicQueryTests.cs deleted file mode 100644 index 42a95f6182bb..000000000000 --- a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/Filter/CosmosNoSqlBasicQueryTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using CosmosNoSql.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace CosmosNoSql.ConformanceTests.Filter; - -public class CosmosNoSqlBasicQueryTests(CosmosNoSqlBasicQueryTests.Fixture fixture) - : BasicQueryTests(fixture), IClassFixture -{ - public new class Fixture : BasicQueryTests.QueryFixture - { - public override TestStore TestStore => CosmosNoSqlTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/ModelTests/CosmosNoSqlBasicModelTests.cs b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/ModelTests/CosmosNoSqlBasicModelTests.cs new file mode 100644 index 000000000000..728745c99f34 --- /dev/null +++ b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/ModelTests/CosmosNoSqlBasicModelTests.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft. All rights reserved. + +using CosmosNoSql.ConformanceTests.Support; +using Microsoft.Azure.Cosmos; +using Microsoft.Extensions.VectorData; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace CosmosNoSql.ConformanceTests.ModelTests; + +public class CosmosNoSqlBasicModelTests(CosmosNoSqlBasicModelTests.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public override async Task GetAsync_with_filter_and_multiple_OrderBys() + { + // CosmosException: The order by query does not have a corresponding composite index that it can be served from. + var exception = await Assert.ThrowsAsync(base.GetAsync_with_filter_and_multiple_OrderBys); + Assert.IsType(exception.InnerException); + } + + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => CosmosNoSqlTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/ModelTests/CosmosNoSqlDynamicModelTests.cs b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/ModelTests/CosmosNoSqlDynamicModelTests.cs new file mode 100644 index 000000000000..8bfadf413ad3 --- /dev/null +++ b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/ModelTests/CosmosNoSqlDynamicModelTests.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft. All rights reserved. + +using CosmosNoSql.ConformanceTests.Support; +using Microsoft.Azure.Cosmos; +using Microsoft.Extensions.VectorData; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace CosmosNoSql.ConformanceTests.ModelTests; + +public class CosmosNoSqlDynamicModelTests(CosmosNoSqlDynamicModelTests.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public override async Task GetAsync_with_filter_and_multiple_OrderBys() + { + // CosmosException: The order by query does not have a corresponding composite index that it can be served from. + var exception = await Assert.ThrowsAsync(base.GetAsync_with_filter_and_multiple_OrderBys); + Assert.IsType(exception.InnerException); + } + + public new class Fixture : DynamicModelTests.Fixture + { + public override TestStore TestStore => CosmosNoSqlTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/ModelTests/CosmosNoSqlNoDataModelTests.cs b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/ModelTests/CosmosNoSqlNoDataModelTests.cs new file mode 100644 index 000000000000..6d87a7bfe6dd --- /dev/null +++ b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/ModelTests/CosmosNoSqlNoDataModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using CosmosNoSql.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace CosmosNoSql.ConformanceTests.ModelTests; + +public class CosmosNoSqlNoDataModelTests(CosmosNoSqlNoDataModelTests.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public new class Fixture : NoDataModelTests.Fixture + { + public override TestStore TestStore => CosmosNoSqlTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/ModelTests/CosmosNoSqlNoVectorConformanceTests.cs b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/ModelTests/CosmosNoSqlNoVectorConformanceTests.cs new file mode 100644 index 000000000000..450d4c2aca5e --- /dev/null +++ b/dotnet/test/VectorData/CosmosNoSql.ConformanceTests/ModelTests/CosmosNoSqlNoVectorConformanceTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using CosmosNoSql.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace CosmosNoSql.ConformanceTests.ModelTests; + +public class CosmosNoSqlNoVectorModelTests(CosmosNoSqlNoVectorModelTests.Fixture fixture) + : NoVectorModelTests(fixture), IClassFixture +{ + public new class Fixture : NoVectorModelTests.Fixture + { + public override TestStore TestStore => CosmosNoSqlTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryBatchConformanceTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryBatchConformanceTests.cs deleted file mode 100644 index be534a42368c..000000000000 --- a/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryBatchConformanceTests.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using InMemory.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace InMemory.ConformanceTests.CRUD; - -public class InMemoryBatchConformanceTests(InMemorySimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture -{ - // InMemory always returns the vectors (IncludeVectors = false isn't respected) - public override async Task GetBatchAsync_WithoutVectors() - { - var expectedRecords = fixture.TestData.Take(2); // the last two records can get deleted by other tests - var ids = expectedRecords.Select(record => record.Id); - - var received = await fixture.Collection.GetAsync(ids, new() { IncludeVectors = false }).ToArrayAsync(); - - foreach (var record in expectedRecords) - { - record.AssertEqual(this.GetRecord(received, record.Id), includeVectors: true, fixture.TestStore.VectorsComparable); - } - } -} diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryDynamicRecordConformanceTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryDynamicRecordConformanceTests.cs deleted file mode 100644 index 4bbf2e2278a4..000000000000 --- a/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryDynamicRecordConformanceTests.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using InMemory.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace InMemory.ConformanceTests.CRUD; - -public class InMemoryDynamicRecordConformanceTests(InMemoryDynamicDataModelFixture fixture) - : DynamicDataModelConformanceTests(fixture), IClassFixture -{ - // InMemory always returns the vectors (IncludeVectors = false isn't respected) - public override async Task GetAsync_WithoutVectors() - { - var expectedRecord = fixture.TestData[0]; - - var received = await fixture.Collection.GetAsync( - (int)expectedRecord[DynamicDataModelFixture.KeyPropertyName]!, - new() { IncludeVectors = false }); - - AssertEquivalent(expectedRecord, received, includeVectors: true, fixture.TestStore.VectorsComparable); - } -} diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryNoDataConformanceTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryNoDataConformanceTests.cs deleted file mode 100644 index 5696ce87f534..000000000000 --- a/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryNoDataConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using InMemory.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace InMemory.ConformanceTests.CRUD; - -public class InMemoryNoDataConformanceTests(InMemoryNoDataConformanceTests.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoDataConformanceTests.Fixture - { - public override TestStore TestStore => InMemoryTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryNoVectorConformanceTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryNoVectorConformanceTests.cs deleted file mode 100644 index a16a0f884c30..000000000000 --- a/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryNoVectorConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using InMemory.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace InMemory.ConformanceTests.CRUD; - -public class InMemoryNoVectorConformanceTests(InMemoryNoVectorConformanceTests.Fixture fixture) - : NoVectorConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoVectorConformanceTests.Fixture - { - public override TestStore TestStore => InMemoryTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryRecordConformanceTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryRecordConformanceTests.cs deleted file mode 100644 index 3756f68ee156..000000000000 --- a/dotnet/test/VectorData/InMemory.ConformanceTests/CRUD/InMemoryRecordConformanceTests.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using InMemory.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace InMemory.ConformanceTests.CRUD; - -public class InMemoryRecordConformanceTests(InMemorySimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture -{ - // InMemory always returns the vectors (IncludeVectors = false isn't respected) - public override async Task GetAsync_WithoutVectors() - { - var expectedRecord = fixture.TestData[0]; - var received = await fixture.Collection.GetAsync(expectedRecord.Id, new() { IncludeVectors = false }); - - expectedRecord.AssertEqual(received, includeVectors: true, fixture.TestStore.VectorsComparable); - } -} diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/Collections/InMemoryCollectionConformanceTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/Collections/InMemoryCollectionConformanceTests.cs deleted file mode 100644 index d6b098c5a689..000000000000 --- a/dotnet/test/VectorData/InMemory.ConformanceTests/Collections/InMemoryCollectionConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using InMemory.ConformanceTests.Support; -using VectorData.ConformanceTests.Collections; -using Xunit; - -namespace InMemory.ConformanceTests.Collections; - -public class InMemoryCollectionConformanceTests(InMemoryFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/Filter/InMemoryBasicFilterTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/Filter/InMemoryBasicFilterTests.cs deleted file mode 100644 index 43b17e623cfd..000000000000 --- a/dotnet/test/VectorData/InMemory.ConformanceTests/Filter/InMemoryBasicFilterTests.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using InMemory.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace InMemory.ConformanceTests.Filter; - -public class InMemoryBasicFilterTests(InMemoryBasicFilterTests.Fixture fixture) - : BasicFilterTests(fixture), IClassFixture -{ - public new class Fixture : BasicFilterTests.Fixture - { - public override TestStore TestStore => InMemoryTestStore.Instance; - - // BaseFilterTests attempts to create two InMemoryVectorStoreRecordCollection with different .NET types: - // 1. One for strongly-typed mapping (TRecord=FilterRecord) - // 2. One for dynamic mapping (TRecord=Dictionary) - // Unfortunately, InMemoryVectorStore does not allow mapping the same collection name to different types; - // at the same time, it simply evaluates all filtering via .NET AsQueryable(), so actual test coverage - // isn't very important here. So we disable the dynamic tests. - public override bool TestDynamic => false; - } -} diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/InMemoryCollectionManagementTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/InMemoryCollectionManagementTests.cs new file mode 100644 index 000000000000..d70e4d7340ff --- /dev/null +++ b/dotnet/test/VectorData/InMemory.ConformanceTests/InMemoryCollectionManagementTests.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. + +using InMemory.ConformanceTests.Support; +using VectorData.ConformanceTests; +using Xunit; + +namespace InMemory.ConformanceTests; + +public class InMemoryCollectionManagementTests(InMemoryFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/Filter/InMemoryBasicQueryTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/InMemoryFilterTests.cs similarity index 73% rename from dotnet/test/VectorData/InMemory.ConformanceTests/Filter/InMemoryBasicQueryTests.cs rename to dotnet/test/VectorData/InMemory.ConformanceTests/InMemoryFilterTests.cs index ad536e8648a6..0b73fa5665a9 100644 --- a/dotnet/test/VectorData/InMemory.ConformanceTests/Filter/InMemoryBasicQueryTests.cs +++ b/dotnet/test/VectorData/InMemory.ConformanceTests/InMemoryFilterTests.cs @@ -1,16 +1,16 @@ // Copyright (c) Microsoft. All rights reserved. using InMemory.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; +using VectorData.ConformanceTests; using VectorData.ConformanceTests.Support; using Xunit; -namespace InMemory.ConformanceTests.Filter; +namespace InMemory.ConformanceTests; -public class InMemoryBasicQueryTests(InMemoryBasicQueryTests.Fixture fixture) - : BasicQueryTests(fixture), IClassFixture +public class InMemoryFilterTests(InMemoryFilterTests.Fixture fixture) + : FilterTests(fixture), IClassFixture { - public new class Fixture : BasicQueryTests.QueryFixture + public new class Fixture : FilterTests.Fixture { public override TestStore TestStore => InMemoryTestStore.Instance; diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/ModelTests/InMemoryBasicModelTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/ModelTests/InMemoryBasicModelTests.cs new file mode 100644 index 000000000000..cc30b26c1c72 --- /dev/null +++ b/dotnet/test/VectorData/InMemory.ConformanceTests/ModelTests/InMemoryBasicModelTests.cs @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft. All rights reserved. + +using InMemory.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace InMemory.ConformanceTests.ModelTests; + +public class InMemoryBasicModelTests(InMemoryBasicModelTests.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public override async Task GetAsync_single_record(bool includeVectors) + { + if (includeVectors) + { + await base.GetAsync_single_record(includeVectors); + return; + } + + // InMemory always returns the vectors (IncludeVectors = false isn't respected) + var expectedRecord = fixture.TestData[0]; + var received = await fixture.Collection.GetAsync(expectedRecord.Key, new() { IncludeVectors = false }); + + expectedRecord.AssertEqual(received, includeVectors: true, fixture.TestStore.VectorsComparable); + } + + public override async Task GetAsync_multiple_records(bool includeVectors) + { + if (includeVectors) + { + await base.GetAsync_multiple_records(includeVectors); + return; + } + + // InMemory always returns the vectors (IncludeVectors = false isn't respected) + var expectedRecords = fixture.TestData.Take(2); // the last two records can get deleted by other tests + var ids = expectedRecords.Select(record => record.Key); + + var received = await fixture.Collection.GetAsync(ids, new() { IncludeVectors = false }).ToArrayAsync(); + + foreach (var record in expectedRecords) + { + record.AssertEqual( + received.Single(r => r.Key.Equals(record.Key)), + includeVectors: true, + fixture.TestStore.VectorsComparable); + } + } + + public override async Task GetAsync_with_filter(bool includeVectors) + { + if (includeVectors) + { + await base.GetAsync_with_filter(includeVectors); + return; + } + + // InMemory always returns the vectors (IncludeVectors = false isn't respected) + var expectedRecord = fixture.TestData[0]; + + var results = await this.Collection.GetAsync( + r => r.Number == 1, + top: 2, + new() { IncludeVectors = includeVectors }) + .ToListAsync(); + + var receivedRecord = Assert.Single(results); + expectedRecord.AssertEqual(receivedRecord, includeVectors: true, fixture.TestStore.VectorsComparable); + } + + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => InMemoryTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/ModelTests/InMemoryDynamicModelTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/ModelTests/InMemoryDynamicModelTests.cs new file mode 100644 index 000000000000..7f2c7d073e22 --- /dev/null +++ b/dotnet/test/VectorData/InMemory.ConformanceTests/ModelTests/InMemoryDynamicModelTests.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft. All rights reserved. + +using InMemory.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace InMemory.ConformanceTests.ModelTests; + +public class InMemoryDynamicModelTests(InMemoryDynamicModelTests.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public override async Task GetAsync_single_record(bool includeVectors) + { + if (includeVectors) + { + await base.GetAsync_single_record(includeVectors); + return; + } + + // InMemory always returns the vectors (IncludeVectors = false isn't respected) + var expectedRecord = fixture.TestData[0]; + var received = await fixture.Collection.GetAsync( + (int)expectedRecord[DynamicDataModelFixture.KeyPropertyName]!, + new() { IncludeVectors = false }); + + AssertEquivalent(expectedRecord, received, includeVectors: true, fixture.TestStore.VectorsComparable); + } + + public override async Task GetAsync_with_filter(bool includeVectors) + { + if (includeVectors) + { + await base.GetAsync_with_filter(includeVectors); + return; + } + + // InMemory always returns the vectors (IncludeVectors = false isn't respected) + var expectedRecord = fixture.TestData[0]; + + var results = await fixture.Collection.GetAsync( + r => (int)r[IntegerPropertyName]! == 1, + top: 2, + new() { IncludeVectors = includeVectors }) + .ToListAsync(); + + var receivedRecord = Assert.Single(results); + AssertEquivalent(expectedRecord, receivedRecord, includeVectors: true, fixture.TestStore.VectorsComparable); + } + + public new class Fixture : DynamicModelTests.Fixture + { + public override TestStore TestStore => InMemoryTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/ModelTests/InMemoryNoDataModelTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/ModelTests/InMemoryNoDataModelTests.cs new file mode 100644 index 000000000000..77a7dd254e78 --- /dev/null +++ b/dotnet/test/VectorData/InMemory.ConformanceTests/ModelTests/InMemoryNoDataModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using InMemory.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace InMemory.ConformanceTests.ModelTests; + +public class InMemoryNoDataModelTests(InMemoryNoDataModelTests.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public new class Fixture : NoDataModelTests.Fixture + { + public override TestStore TestStore => InMemoryTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/InMemory.ConformanceTests/ModelTests/InMemoryNoVectorModelTests.cs b/dotnet/test/VectorData/InMemory.ConformanceTests/ModelTests/InMemoryNoVectorModelTests.cs new file mode 100644 index 000000000000..fe9b1b4a6d87 --- /dev/null +++ b/dotnet/test/VectorData/InMemory.ConformanceTests/ModelTests/InMemoryNoVectorModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using InMemory.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace InMemory.ConformanceTests.ModelTests; + +public class InMemoryNoVectorModelTests(InMemoryNoVectorModelTests.Fixture fixture) + : NoVectorModelTests(fixture), IClassFixture +{ + public new class Fixture : NoVectorModelTests.Fixture + { + public override TestStore TestStore => InMemoryTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/CRUD/MongoBatchConformanceTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/CRUD/MongoBatchConformanceTests.cs deleted file mode 100644 index 307a79479f6a..000000000000 --- a/dotnet/test/VectorData/MongoDB.ConformanceTests/CRUD/MongoBatchConformanceTests.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using MongoDB.Bson; -using MongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace MongoDB.ConformanceTests.CRUD; - -public class MongoBatchConformanceTests_String(MongoSimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture> -{ -} - -public class MongoBatchConformanceTests_Guid(MongoSimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture> -{ -} - -public class MongoBatchConformanceTests_ObjectId(MongoSimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture> -{ -} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/CRUD/MongoNoDataConformanceTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/CRUD/MongoNoDataConformanceTests.cs deleted file mode 100644 index ee3ad6a5e526..000000000000 --- a/dotnet/test/VectorData/MongoDB.ConformanceTests/CRUD/MongoNoDataConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using MongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace MongoDB.ConformanceTests.CRUD; - -public class MongoNoDataConformanceTests(MongoNoDataConformanceTests.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoDataConformanceTests.Fixture - { - public override TestStore TestStore => MongoTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/CRUD/MongoNoVectorConformanceTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/CRUD/MongoNoVectorConformanceTests.cs deleted file mode 100644 index 9f01003d3311..000000000000 --- a/dotnet/test/VectorData/MongoDB.ConformanceTests/CRUD/MongoNoVectorConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using MongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace MongoDB.ConformanceTests.CRUD; - -public class MongoNoVectorConformanceTests(MongoNoVectorConformanceTests.Fixture fixture) - : NoVectorConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoVectorConformanceTests.Fixture - { - public override TestStore TestStore => MongoTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/CRUD/MongoRecordConformanceTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/CRUD/MongoRecordConformanceTests.cs deleted file mode 100644 index 171676cceb46..000000000000 --- a/dotnet/test/VectorData/MongoDB.ConformanceTests/CRUD/MongoRecordConformanceTests.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using MongoDB.Bson; -using MongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace MongoDB.ConformanceTests.CRUD; - -public class MongoRecordConformanceTests_String(MongoSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture> -{ -} - -public class MongoRecordConformanceTests_Guid(MongoSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture> -{ -} - -public class MongoRecordConformanceTests_ObjectId(MongoSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture> -{ -} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/Collections/MongoCollectionConformanceTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/Collections/MongoCollectionConformanceTests.cs deleted file mode 100644 index 70bc53d5b4a8..000000000000 --- a/dotnet/test/VectorData/MongoDB.ConformanceTests/Collections/MongoCollectionConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using MongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.Collections; -using Xunit; - -namespace MongoDB.ConformanceTests.Collections; - -public class MongoCollectionConformanceTests(MongoFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/Filter/MongoBasicFilterTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/Filter/MongoBasicFilterTests.cs deleted file mode 100644 index 6e6cca078895..000000000000 --- a/dotnet/test/VectorData/MongoDB.ConformanceTests/Filter/MongoBasicFilterTests.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using MongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using VectorData.ConformanceTests.Xunit; -using Xunit; - -namespace MongoDB.ConformanceTests.Filter; - -public class MongoBasicFilterTests(MongoBasicFilterTests.Fixture fixture) - : BasicFilterTests(fixture), IClassFixture -{ - // Specialized MongoDB syntax for NOT over Contains ($nin) - [ConditionalFact] - public virtual Task Not_over_Contains() - => this.TestFilterAsync( - r => !new[] { 8, 10 }.Contains(r.Int), - r => !new[] { 8, 10 }.Contains((int)r["Int"]!)); - - #region Null checking - - // MongoDB currently doesn't support null checking ({ "Foo" : null }) in vector search pre-filters - public override Task Equal_with_null_reference_type() - => Assert.ThrowsAsync(() => base.Equal_with_null_reference_type()); - - public override Task Equal_with_null_captured() - => Assert.ThrowsAsync(() => base.Equal_with_null_captured()); - - public override Task NotEqual_with_null_reference_type() - => Assert.ThrowsAsync(() => base.NotEqual_with_null_reference_type()); - - public override Task NotEqual_with_null_captured() - => Assert.ThrowsAsync(() => base.NotEqual_with_null_captured()); - - public override Task Equal_int_property_with_null_nullable_int() - => Assert.ThrowsAsync(() => base.Equal_int_property_with_null_nullable_int()); - - #endregion - - #region Not - - // MongoDB currently doesn't support NOT in vector search pre-filters - // (https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/#atlas-vector-search-pre-filter) - public override Task Not_over_And() - => Assert.ThrowsAsync(() => base.Not_over_And()); - - public override Task Not_over_Or() - => Assert.ThrowsAsync(() => base.Not_over_Or()); - - #endregion - - public override Task Contains_over_field_string_array() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_array()); - - public override Task Contains_over_field_string_List() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_List()); - - // AnyTagEqualTo not (currently) supported on SQLite - [Obsolete("Legacy filter support")] - public override Task Legacy_AnyTagEqualTo_array() - => Assert.ThrowsAsync(() => base.Legacy_AnyTagEqualTo_array()); - - [Obsolete("Legacy filter support")] - public override Task Legacy_AnyTagEqualTo_List() - => Assert.ThrowsAsync(() => base.Legacy_AnyTagEqualTo_List()); - - public new class Fixture : BasicFilterTests.Fixture - { - public override TestStore TestStore => MongoTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/Filter/MongoBasicQueryTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/Filter/MongoBasicQueryTests.cs deleted file mode 100644 index ab52db34f11e..000000000000 --- a/dotnet/test/VectorData/MongoDB.ConformanceTests/Filter/MongoBasicQueryTests.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using MongoDB.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using VectorData.ConformanceTests.Xunit; -using Xunit; - -namespace MongoDB.ConformanceTests.Filter; - -public class MongoBasicQueryTests(MongoBasicQueryTests.Fixture fixture) - : BasicQueryTests(fixture), IClassFixture -{ - // Specialized MongoDB syntax for NOT over Contains ($nin) - [ConditionalFact] - public virtual Task Not_over_Contains() - => this.TestFilterAsync( - r => !new[] { 8, 10 }.Contains(r.Int), - r => !new[] { 8, 10 }.Contains((int)r["Int"]!)); - - // MongoDB currently doesn't support null checking ({ "Foo" : null }) in vector search pre-filters - public override Task Equal_with_null_reference_type() - => Assert.ThrowsAsync(() => base.Equal_with_null_reference_type()); - - public override Task Equal_with_null_captured() - => Assert.ThrowsAsync(() => base.Equal_with_null_captured()); - - public override Task NotEqual_with_null_reference_type() - => Assert.ThrowsAsync(() => base.NotEqual_with_null_reference_type()); - - public override Task NotEqual_with_null_captured() - => Assert.ThrowsAsync(() => base.NotEqual_with_null_captured()); - - public override Task Equal_int_property_with_null_nullable_int() - => Assert.ThrowsAsync(() => base.Equal_int_property_with_null_nullable_int()); - - // MongoDB currently doesn't support NOT in vector search pre-filters - // (https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/#atlas-vector-search-pre-filter) - public override Task Not_over_And() - => Assert.ThrowsAsync(() => base.Not_over_And()); - - public override Task Not_over_Or() - => Assert.ThrowsAsync(() => base.Not_over_Or()); - - public override Task Contains_over_field_string_array() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_array()); - - public override Task Contains_over_field_string_List() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_List()); - - public new class Fixture : BasicQueryTests.QueryFixture - { - public override TestStore TestStore => MongoTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/ModelTests/MongoBasicModelTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/ModelTests/MongoBasicModelTests.cs new file mode 100644 index 000000000000..474987586a08 --- /dev/null +++ b/dotnet/test/VectorData/MongoDB.ConformanceTests/ModelTests/MongoBasicModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using MongoDB.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace MongoDB.ConformanceTests.ModelTests; + +public class MongoBasicModelTests(MongoBasicModelTests.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => MongoTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/ModelTests/MongoDynamicModelTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/ModelTests/MongoDynamicModelTests.cs new file mode 100644 index 000000000000..6253b5e680fd --- /dev/null +++ b/dotnet/test/VectorData/MongoDB.ConformanceTests/ModelTests/MongoDynamicModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using MongoDB.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace MongoDB.ConformanceTests.ModelTests; + +public class MongoDynamicModelTests(MongoDynamicModelTests.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public new class Fixture : DynamicModelTests.Fixture + { + public override TestStore TestStore => MongoTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/ModelTests/MongoNoDataModelTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/ModelTests/MongoNoDataModelTests.cs new file mode 100644 index 000000000000..13f2c57c65f7 --- /dev/null +++ b/dotnet/test/VectorData/MongoDB.ConformanceTests/ModelTests/MongoNoDataModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using MongoDB.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace MongoDB.ConformanceTests.ModelTests; + +public class MongoNoDataModelTests(MongoNoDataModelTests.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public new class Fixture : NoDataModelTests.Fixture + { + public override TestStore TestStore => MongoTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/ModelTests/MongoNoVectorConformanceTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/ModelTests/MongoNoVectorConformanceTests.cs new file mode 100644 index 000000000000..8b8654c5621a --- /dev/null +++ b/dotnet/test/VectorData/MongoDB.ConformanceTests/ModelTests/MongoNoVectorConformanceTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using MongoDB.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace MongoDB.ConformanceTests.ModelTests; + +public class MongoNoVectorModelTests(MongoNoVectorModelTests.Fixture fixture) + : NoVectorModelTests(fixture), IClassFixture +{ + public new class Fixture : NoVectorModelTests.Fixture + { + public override TestStore TestStore => MongoTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/MongoCollectionManagementTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/MongoCollectionManagementTests.cs new file mode 100644 index 000000000000..e118f8fedb59 --- /dev/null +++ b/dotnet/test/VectorData/MongoDB.ConformanceTests/MongoCollectionManagementTests.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. + +using MongoDB.ConformanceTests.Support; +using VectorData.ConformanceTests; +using Xunit; + +namespace MongoDB.ConformanceTests; + +public class MongoCollectionManagementTests(MongoFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/MongoFilterTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/MongoFilterTests.cs new file mode 100644 index 000000000000..d102528334f0 --- /dev/null +++ b/dotnet/test/VectorData/MongoDB.ConformanceTests/MongoFilterTests.cs @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft. All rights reserved. + +using MongoDB.ConformanceTests.Support; +using VectorData.ConformanceTests; +using VectorData.ConformanceTests.Support; +using VectorData.ConformanceTests.Xunit; +using Xunit; + +namespace MongoDB.ConformanceTests; + +public class MongoFilterTests(MongoFilterTests.Fixture fixture) + : FilterTests(fixture), IClassFixture +{ + // Specialized MongoDB syntax for NOT over Contains ($nin) + [ConditionalFact] + public virtual Task Not_over_Contains() + => this.TestFilterAsync( + r => !new[] { 8, 10 }.Contains(r.Int), + r => !new[] { 8, 10 }.Contains((int)r["Int"]!)); + + #region Null checking + + // MongoDB currently doesn't support null checking ({ "Foo" : null }) in vector search pre-filters + public override Task Equal_with_null_reference_type() + => Assert.ThrowsAsync(base.Equal_with_null_reference_type); + + public override Task Equal_with_null_captured() + => Assert.ThrowsAsync(base.Equal_with_null_captured); + + public override Task NotEqual_with_null_reference_type() + => Assert.ThrowsAsync(base.NotEqual_with_null_reference_type); + + public override Task NotEqual_with_null_captured() + => Assert.ThrowsAsync(base.NotEqual_with_null_captured); + + public override Task Equal_int_property_with_null_nullable_int() + => Assert.ThrowsAsync(base.Equal_int_property_with_null_nullable_int); + + #endregion + + #region Not + + // MongoDB currently doesn't support NOT in vector search pre-filters + // (https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/#atlas-vector-search-pre-filter) + public override Task Not_over_And() + => Assert.ThrowsAsync(base.Not_over_And); + + public override Task Not_over_Or() + => Assert.ThrowsAsync(base.Not_over_Or); + + #endregion + + public override Task Contains_over_field_string_array() + => Assert.ThrowsAsync(base.Contains_over_field_string_array); + + public override Task Contains_over_field_string_List() + => Assert.ThrowsAsync(base.Contains_over_field_string_List); + + public override Task Contains_with_Enumerable_Contains() + => Assert.ThrowsAsync(base.Contains_with_Enumerable_Contains); + +#if !NETFRAMEWORK + public override Task Contains_with_MemoryExtensions_Contains() + => Assert.ThrowsAsync(base.Contains_with_MemoryExtensions_Contains); +#endif + +#if NET10_0_OR_GREATER + [ConditionalFact] + public virtual Task Contains_with_MemoryExtensions_Contains_with_null_comparer() + => Assert.ThrowsAsync(base.Contains_with_MemoryExtensions_Contains_with_null_comparer); +#endif + + // AnyTagEqualTo not (currently) supported on SQLite + [Obsolete("Legacy filter support")] + public override Task Legacy_AnyTagEqualTo_array() + => Assert.ThrowsAsync(base.Legacy_AnyTagEqualTo_array); + + [Obsolete("Legacy filter support")] + public override Task Legacy_AnyTagEqualTo_List() + => Assert.ThrowsAsync(base.Legacy_AnyTagEqualTo_List); + + public new class Fixture : FilterTests.Fixture + { + public override TestStore TestStore => MongoTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/MongoDB.ConformanceTests/MongoTestSuiteImplementationTests.cs b/dotnet/test/VectorData/MongoDB.ConformanceTests/MongoTestSuiteImplementationTests.cs index 8ed44371b6ed..a5e577d88e0e 100644 --- a/dotnet/test/VectorData/MongoDB.ConformanceTests/MongoTestSuiteImplementationTests.cs +++ b/dotnet/test/VectorData/MongoDB.ConformanceTests/MongoTestSuiteImplementationTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. using VectorData.ConformanceTests; -using VectorData.ConformanceTests.CRUD; using VectorData.ConformanceTests.VectorSearch; namespace MongoDB.ConformanceTests; @@ -11,7 +10,6 @@ public class MongoTestSuiteImplementationTests : TestSuiteImplementationTests protected override ICollection IgnoredTestBases { get; } = [ typeof(VectorSearchDistanceFunctionComplianceTests<>), - typeof(VectorSearchWithFilterConformanceTests<>), - typeof(DynamicDataModelConformanceTests<>), + typeof(VectorSearchWithFilterConformanceTests<>) ]; } diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresBatchConformanceTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresBatchConformanceTests.cs deleted file mode 100644 index 518ac95bc3a1..000000000000 --- a/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresBatchConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using PgVector.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace PgVector.ConformanceTests.CRUD; - -public class PostgresBatchConformanceTests(PostgresSimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresDynamicDataModelConformanceTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresDynamicDataModelConformanceTests.cs deleted file mode 100644 index 9ef3e347435a..000000000000 --- a/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresDynamicDataModelConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using PgVector.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace PgVector.ConformanceTests.CRUD; - -public class PostgresDynamicDataModelConformanceTests(PostgresDynamicDataModelFixture fixture) - : DynamicDataModelConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresNoDataConformanceTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresNoDataConformanceTests.cs deleted file mode 100644 index ea5a5122f83c..000000000000 --- a/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresNoDataConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using PgVector.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace PgVector.ConformanceTests.CRUD; - -public class PostgresNoDataConformanceTests(PostgresNoDataConformanceTests.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoDataConformanceTests.Fixture - { - public override TestStore TestStore => PostgresTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresNoVectorConformanceTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresNoVectorConformanceTests.cs deleted file mode 100644 index cc51d8eca4c1..000000000000 --- a/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresNoVectorConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using PgVector.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace PgVector.ConformanceTests.CRUD; - -public class PostgresNoVectorConformanceTests(PostgresNoVectorConformanceTests.Fixture fixture) - : NoVectorConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoVectorConformanceTests.Fixture - { - public override TestStore TestStore => PostgresTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresRecordConformanceTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresRecordConformanceTests.cs deleted file mode 100644 index 6b7ad004c609..000000000000 --- a/dotnet/test/VectorData/PgVector.ConformanceTests/CRUD/PostgresRecordConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using PgVector.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace PgVector.ConformanceTests.CRUD; - -public class PostgresRecordConformanceTests(PostgresSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/Collections/PostgresCollectionConformanceTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/Collections/PostgresCollectionConformanceTests.cs deleted file mode 100644 index 088962162195..000000000000 --- a/dotnet/test/VectorData/PgVector.ConformanceTests/Collections/PostgresCollectionConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using PgVector.ConformanceTests.Support; -using VectorData.ConformanceTests.Collections; -using Xunit; - -namespace PgVector.ConformanceTests.Collections; - -public class PostgresCollectionConformanceTests(PostgresFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/Filter/PostgresBasicQueryTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/Filter/PostgresBasicQueryTests.cs deleted file mode 100644 index 8bc2677c890e..000000000000 --- a/dotnet/test/VectorData/PgVector.ConformanceTests/Filter/PostgresBasicQueryTests.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using PgVector.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using Xunit; -using Xunit.Sdk; - -namespace PgVector.ConformanceTests.Filter; - -#pragma warning disable CS0252 // Possible unintended reference comparison; left hand side needs cast - -public class PostgresBasicQueryTests(PostgresBasicQueryTests.Fixture fixture) - : BasicQueryTests(fixture), IClassFixture -{ - public override async Task Not_over_Or() - { - // Test sends: WHERE (NOT (("Int" = 8) OR ("String" = 'foo'))) - // There's a NULL string in the database, and relational null semantics in conjunction with negation makes the default implementation fail. - await Assert.ThrowsAsync(() => base.Not_over_Or()); - - // Compensate by adding a null check: - await this.TestFilterAsync( - r => r.String != null && !(r.Int == 8 || r.String == "foo"), - r => r["String"] != null && !((int)r["Int"]! == 8 || r["String"] == "foo")); - } - - public override async Task NotEqual_with_string() - { - // As above, null semantics + negation - await Assert.ThrowsAsync(() => base.NotEqual_with_string()); - - await this.TestFilterAsync( - r => r.String != null && r.String != "foo", - r => r["String"] != null && r["String"] != "foo"); - } - - public new class Fixture : BasicQueryTests.QueryFixture - { - public override TestStore TestStore => PostgresTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/ModelTests/PostgresBasicModelTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/ModelTests/PostgresBasicModelTests.cs new file mode 100644 index 000000000000..919a604f09d4 --- /dev/null +++ b/dotnet/test/VectorData/PgVector.ConformanceTests/ModelTests/PostgresBasicModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using PgVector.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace PgVector.ConformanceTests.ModelTests; + +public class PostgresBasicModelTests(PostgresBasicModelTests.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => PostgresTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/ModelTests/PostgresDynamicModelTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/ModelTests/PostgresDynamicModelTests.cs new file mode 100644 index 000000000000..1f6b0ed14f31 --- /dev/null +++ b/dotnet/test/VectorData/PgVector.ConformanceTests/ModelTests/PostgresDynamicModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using PgVector.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace PgVector.ConformanceTests.ModelTests; + +public class PostgresDynamicModelTests(PostgresDynamicModelTests.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public new class Fixture : DynamicModelTests.Fixture + { + public override TestStore TestStore => PostgresTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/ModelTests/PostgresNoDataModelTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/ModelTests/PostgresNoDataModelTests.cs new file mode 100644 index 000000000000..ee0e30dbe277 --- /dev/null +++ b/dotnet/test/VectorData/PgVector.ConformanceTests/ModelTests/PostgresNoDataModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using PgVector.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace PgVector.ConformanceTests.ModelTests; + +public class PostgresNoDataModelTests(PostgresNoDataModelTests.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public new class Fixture : NoDataModelTests.Fixture + { + public override TestStore TestStore => PostgresTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/ModelTests/PostgresNoVectorModelTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/ModelTests/PostgresNoVectorModelTests.cs new file mode 100644 index 000000000000..1c4dab3e5ff3 --- /dev/null +++ b/dotnet/test/VectorData/PgVector.ConformanceTests/ModelTests/PostgresNoVectorModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using PgVector.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace PgVector.ConformanceTests.ModelTests; + +public class PostgresNoVectorModelTests(PostgresNoVectorModelTests.Fixture fixture) + : NoVectorModelTests(fixture), IClassFixture +{ + public new class Fixture : NoVectorModelTests.Fixture + { + public override TestStore TestStore => PostgresTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/PostgresCollectionManagementTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/PostgresCollectionManagementTests.cs new file mode 100644 index 000000000000..e573e309c396 --- /dev/null +++ b/dotnet/test/VectorData/PgVector.ConformanceTests/PostgresCollectionManagementTests.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. + +using PgVector.ConformanceTests.Support; +using VectorData.ConformanceTests; +using Xunit; + +namespace PgVector.ConformanceTests; + +public class PostgresCollectionManagementTests(PostgresFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/Filter/PostgresBasicFilterTests.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/PostgresFilterTests.cs similarity index 82% rename from dotnet/test/VectorData/PgVector.ConformanceTests/Filter/PostgresBasicFilterTests.cs rename to dotnet/test/VectorData/PgVector.ConformanceTests/PostgresFilterTests.cs index 500fcbd6fd3c..256f1e37481e 100644 --- a/dotnet/test/VectorData/PgVector.ConformanceTests/Filter/PostgresBasicFilterTests.cs +++ b/dotnet/test/VectorData/PgVector.ConformanceTests/PostgresFilterTests.cs @@ -1,17 +1,17 @@ // Copyright (c) Microsoft. All rights reserved. using PgVector.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; +using VectorData.ConformanceTests; using VectorData.ConformanceTests.Support; using Xunit; using Xunit.Sdk; -namespace PgVector.ConformanceTests.Filter; +namespace PgVector.ConformanceTests; #pragma warning disable CS0252 // Possible unintended reference comparison; left hand side needs cast -public class PostgresBasicFilterTests(PostgresBasicFilterTests.Fixture fixture) - : BasicFilterTests(fixture), IClassFixture +public class PostgresFilterTests(PostgresFilterTests.Fixture fixture) + : FilterTests(fixture), IClassFixture { public override async Task Not_over_Or() { @@ -39,7 +39,7 @@ await this.TestFilterAsync( public override Task Legacy_AnyTagEqualTo_array() => Assert.ThrowsAsync(() => base.Legacy_AnyTagEqualTo_array()); - public new class Fixture : BasicFilterTests.Fixture + public new class Fixture : FilterTests.Fixture { public override TestStore TestStore => PostgresTestStore.Instance; } diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/Support/PostgresDynamicDataModelFixture.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/Support/PostgresDynamicDataModelFixture.cs deleted file mode 100644 index 396d21c2d20b..000000000000 --- a/dotnet/test/VectorData/PgVector.ConformanceTests/Support/PostgresDynamicDataModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace PgVector.ConformanceTests.Support; - -public class PostgresDynamicDataModelFixture : DynamicDataModelFixture -{ - public override TestStore TestStore => PostgresTestStore.Instance; -} diff --git a/dotnet/test/VectorData/PgVector.ConformanceTests/Support/PostgresSimpleModelFixture.cs b/dotnet/test/VectorData/PgVector.ConformanceTests/Support/PostgresSimpleModelFixture.cs deleted file mode 100644 index 4830798ce7fb..000000000000 --- a/dotnet/test/VectorData/PgVector.ConformanceTests/Support/PostgresSimpleModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace PgVector.ConformanceTests.Support; - -public class PostgresSimpleModelFixture : SimpleModelFixture -{ - public override TestStore TestStore => PostgresTestStore.Instance; -} diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeBatchConformanceTests.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeBatchConformanceTests.cs deleted file mode 100644 index 50ed70cbb094..000000000000 --- a/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeBatchConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Pinecone.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace Pinecone.ConformanceTests.CRUD; - -public class PineconeBatchConformanceTests(PineconeSimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeDynamicDataModelConformanceTests.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeDynamicDataModelConformanceTests.cs deleted file mode 100644 index fa9932734954..000000000000 --- a/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeDynamicDataModelConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Pinecone.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace Pinecone.ConformanceTests.CRUD; - -public class PineconeDynamicDataModelConformanceTests(PineconeDynamicDataModelFixture fixture) - : DynamicDataModelConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeNoDataConformanceTests.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeNoDataConformanceTests.cs deleted file mode 100644 index be3f9b74447b..000000000000 --- a/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeNoDataConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Pinecone.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace Pinecone.ConformanceTests.CRUD; - -public class PineconeNoDataConformanceTests(PineconeNoDataConformanceTests.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoDataConformanceTests.Fixture - { - public override TestStore TestStore => PineconeTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeRecordConformanceTests.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeRecordConformanceTests.cs deleted file mode 100644 index c8915b8c9d15..000000000000 --- a/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeRecordConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Pinecone.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace Pinecone.ConformanceTests.CRUD; - -public class PineconeRecordConformanceTests(PineconeSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/Filter/PineconeBasicQueryTests.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/Filter/PineconeBasicQueryTests.cs deleted file mode 100644 index edf84f370afa..000000000000 --- a/dotnet/test/VectorData/Pinecone.ConformanceTests/Filter/PineconeBasicQueryTests.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Pinecone.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using VectorData.ConformanceTests.Xunit; -using Xunit; - -namespace Pinecone.ConformanceTests.Filter; - -#pragma warning disable CS8605 // Unboxing a possibly null value. - -public class PineconeBasicQueryTests(PineconeBasicQueryTests.Fixture fixture) - : BasicQueryTests(fixture), IClassFixture -{ - // Specialized Pinecone syntax for NOT over Contains ($nin) - [ConditionalFact] - public virtual Task Not_over_Contains() - => this.TestFilterAsync( - r => !new[] { 8, 10 }.Contains(r.Int), - r => !new[] { 8, 10 }.Contains((int)r["Int"])); - - // Pinecone currently doesn't support null checking ({ "Foo" : null }) in vector search pre-filters - public override Task Equal_with_null_reference_type() - => Assert.ThrowsAsync(() => base.Equal_with_null_reference_type()); - - public override Task Equal_with_null_captured() - => Assert.ThrowsAsync(() => base.Equal_with_null_captured()); - - public override Task NotEqual_with_null_reference_type() - => Assert.ThrowsAsync(() => base.NotEqual_with_null_reference_type()); - - public override Task NotEqual_with_null_captured() - => Assert.ThrowsAsync(() => base.NotEqual_with_null_captured()); - - public override Task Equal_int_property_with_null_nullable_int() - => Assert.ThrowsAsync(() => base.Equal_int_property_with_null_nullable_int()); - - // Pinecone currently doesn't support NOT in vector search pre-filters - // (https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/#atlas-vector-search-pre-filter) - public override Task Not_over_And() - => Assert.ThrowsAsync(() => base.Not_over_And()); - - public override Task Not_over_Or() - => Assert.ThrowsAsync(() => base.Not_over_Or()); - - public override Task Contains_over_field_string_array() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_array()); - - public override Task Contains_over_field_string_List() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_List()); - - public new class Fixture : BasicQueryTests.QueryFixture - { - public override TestStore TestStore => PineconeTestStore.Instance; - - // https://docs.pinecone.io/troubleshooting/restrictions-on-index-names - public override string CollectionName => "query-tests"; - } -} diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeAllSupportedTypesTests.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/PineconeAllSupportedTypesTests.cs similarity index 100% rename from dotnet/test/VectorData/Pinecone.ConformanceTests/CRUD/PineconeAllSupportedTypesTests.cs rename to dotnet/test/VectorData/Pinecone.ConformanceTests/PineconeAllSupportedTypesTests.cs diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/Collections/PineconeCollectionConformanceTests.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/PineconeCollectionManagementTests.cs similarity index 50% rename from dotnet/test/VectorData/Pinecone.ConformanceTests/Collections/PineconeCollectionConformanceTests.cs rename to dotnet/test/VectorData/Pinecone.ConformanceTests/PineconeCollectionManagementTests.cs index 355c93ba556b..6bedfb6acc21 100644 --- a/dotnet/test/VectorData/Pinecone.ConformanceTests/Collections/PineconeCollectionConformanceTests.cs +++ b/dotnet/test/VectorData/Pinecone.ConformanceTests/PineconeCollectionManagementTests.cs @@ -1,13 +1,13 @@ // Copyright (c) Microsoft. All rights reserved. using Pinecone.ConformanceTests.Support; -using VectorData.ConformanceTests.Collections; +using VectorData.ConformanceTests; using Xunit; -namespace Pinecone.ConformanceTests.Collections; +namespace Pinecone.ConformanceTests; -public class PineconeCollectionConformanceTests(PineconeFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture +public class PineconeCollectionManagementTests(PineconeFixture fixture) + : CollectionManagementTests(fixture), IClassFixture { // https://docs.pinecone.io/troubleshooting/restrictions-on-index-names public override string CollectionName => "collection-tests"; diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/Filter/PineconeBasicFilterTests.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/PineconeFilterTests.cs similarity index 90% rename from dotnet/test/VectorData/Pinecone.ConformanceTests/Filter/PineconeBasicFilterTests.cs rename to dotnet/test/VectorData/Pinecone.ConformanceTests/PineconeFilterTests.cs index 5aecb4b007fa..0342d871af29 100644 --- a/dotnet/test/VectorData/Pinecone.ConformanceTests/Filter/PineconeBasicFilterTests.cs +++ b/dotnet/test/VectorData/Pinecone.ConformanceTests/PineconeFilterTests.cs @@ -1,17 +1,17 @@ // Copyright (c) Microsoft. All rights reserved. using Pinecone.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; +using VectorData.ConformanceTests; using VectorData.ConformanceTests.Support; using VectorData.ConformanceTests.Xunit; using Xunit; -namespace Pinecone.ConformanceTests.Filter; +namespace Pinecone.ConformanceTests; #pragma warning disable CS8605 // Unboxing a possibly null value. -public class PineconeBasicFilterTests(PineconeBasicFilterTests.Fixture fixture) - : BasicFilterTests(fixture), IClassFixture +public class PineconeFilterTests(PineconeFilterTests.Fixture fixture) + : FilterTests(fixture), IClassFixture { // Specialized Pinecone syntax for NOT over Contains ($nin) [ConditionalFact] @@ -67,7 +67,7 @@ public override Task Legacy_AnyTagEqualTo_array() public override Task Legacy_AnyTagEqualTo_List() => Assert.ThrowsAsync(() => base.Legacy_AnyTagEqualTo_List()); - public new class Fixture : BasicFilterTests.Fixture + public new class Fixture : FilterTests.Fixture { public override TestStore TestStore => PineconeTestStore.Instance; diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/Support/PineconeDynamicDataModelFixture.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/Support/PineconeDynamicDataModelFixture.cs deleted file mode 100644 index a43d5b7bc5c8..000000000000 --- a/dotnet/test/VectorData/Pinecone.ConformanceTests/Support/PineconeDynamicDataModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace Pinecone.ConformanceTests.Support; - -public class PineconeDynamicDataModelFixture : DynamicDataModelFixture -{ - public override TestStore TestStore => PineconeTestStore.Instance; -} diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/Support/PineconeSimpleModelFixture.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/Support/PineconeSimpleModelFixture.cs deleted file mode 100644 index 6d7c8e007b3e..000000000000 --- a/dotnet/test/VectorData/Pinecone.ConformanceTests/Support/PineconeSimpleModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace Pinecone.ConformanceTests.Support; - -public class PineconeSimpleModelFixture : SimpleModelFixture -{ - public override TestStore TestStore => PineconeTestStore.Instance; -} diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/TestModels/PineconeBasicModelTests.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/TestModels/PineconeBasicModelTests.cs new file mode 100644 index 000000000000..859542eead00 --- /dev/null +++ b/dotnet/test/VectorData/Pinecone.ConformanceTests/TestModels/PineconeBasicModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Pinecone.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Pinecone.ConformanceTests.ModelTests; + +public class PineconeBasicModelTests(PineconeBasicModelTests.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => PineconeTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/TestModels/PineconeDynamicModelTests.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/TestModels/PineconeDynamicModelTests.cs new file mode 100644 index 000000000000..c4aff04e3165 --- /dev/null +++ b/dotnet/test/VectorData/Pinecone.ConformanceTests/TestModels/PineconeDynamicModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Pinecone.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Pinecone.ConformanceTests.ModelTests; + +public class PineconeDynamicModelTests(PineconeDynamicModelTests.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public new class Fixture : DynamicModelTests.Fixture + { + public override TestStore TestStore => PineconeTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/Pinecone.ConformanceTests/TestModels/PineconeNoDataModelTests.cs b/dotnet/test/VectorData/Pinecone.ConformanceTests/TestModels/PineconeNoDataModelTests.cs new file mode 100644 index 000000000000..c17149dcdfd1 --- /dev/null +++ b/dotnet/test/VectorData/Pinecone.ConformanceTests/TestModels/PineconeNoDataModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Pinecone.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Pinecone.ConformanceTests.ModelTests; + +public class PineconeNoDataModelTests(PineconeNoDataModelTests.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public new class Fixture : NoDataModelTests.Fixture + { + public override TestStore TestStore => PineconeTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/CRUD/QdrantBatchConformanceTests.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/CRUD/QdrantBatchConformanceTests.cs deleted file mode 100644 index ff2f4017467d..000000000000 --- a/dotnet/test/VectorData/Qdrant.ConformanceTests/CRUD/QdrantBatchConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Qdrant.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace Qdrant.ConformanceTests.CRUD; - -public class QdrantBatchConformanceTests_NamedVectors(QdrantNamedSimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture -{ -} - -public class QdrantBatchConformanceTests_UnnamedVector(QdrantUnnamedSimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/CRUD/QdrantDynamicDataModelConformanceTests.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/CRUD/QdrantDynamicDataModelConformanceTests.cs deleted file mode 100644 index 64e3211984e5..000000000000 --- a/dotnet/test/VectorData/Qdrant.ConformanceTests/CRUD/QdrantDynamicDataModelConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Qdrant.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace Qdrant.ConformanceTests.CRUD; - -public class QdrantDynamicDataModelConformanceTests_NamedVectors(QdrantNamedDynamicDataModelFixture fixture) - : DynamicDataModelConformanceTests(fixture), IClassFixture -{ -} - -public class QdrantDynamicDataModelConformanceTests_UnnamedVector(QdrantUnnamedDynamicDataModelFixture fixture) - : DynamicDataModelConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/CRUD/QdrantNoDataConformanceTests.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/CRUD/QdrantNoDataConformanceTests.cs deleted file mode 100644 index af039b5afea9..000000000000 --- a/dotnet/test/VectorData/Qdrant.ConformanceTests/CRUD/QdrantNoDataConformanceTests.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Qdrant.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace Qdrant.ConformanceTests.CRUD; - -public class QdrantNoDataConformanceTests_NamedVectors(QdrantNoDataConformanceTests_NamedVectors.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoDataConformanceTests.Fixture - { - public override TestStore TestStore => QdrantTestStore.NamedVectorsInstance; - } -} - -public class QdrantNoDataConformanceTests_UnnamedVectors(QdrantNoDataConformanceTests_UnnamedVectors.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoDataConformanceTests.Fixture - { - public override TestStore TestStore => QdrantTestStore.UnnamedVectorInstance; - } -} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/CRUD/QdrantRecordConformanceTests.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/CRUD/QdrantRecordConformanceTests.cs deleted file mode 100644 index e66944fc9fd0..000000000000 --- a/dotnet/test/VectorData/Qdrant.ConformanceTests/CRUD/QdrantRecordConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Qdrant.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace Qdrant.ConformanceTests.CRUD; - -public class QdrantRecordConformanceTests_NamedVectors(QdrantNamedSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture -{ -} - -public class QdrantRecordConformanceTests_UnnamedVectors(QdrantUnnamedSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/Collections/QdrantCollectionConformanceTests.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/Collections/QdrantCollectionConformanceTests.cs deleted file mode 100644 index 1470897e10ca..000000000000 --- a/dotnet/test/VectorData/Qdrant.ConformanceTests/Collections/QdrantCollectionConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Qdrant.ConformanceTests.Support; -using VectorData.ConformanceTests.Collections; -using Xunit; - -namespace Qdrant.ConformanceTests.Collections; - -public class QdrantCollectionConformanceTests_NamedVectors(QdrantNamedVectorsFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} - -public class QdrantCollectionConformanceTests_UnnamedVector(QdrantUnnamedVectorFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/Filter/QdrantBasicFilterTests.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/Filter/QdrantBasicFilterTests.cs deleted file mode 100644 index b80da73b1d74..000000000000 --- a/dotnet/test/VectorData/Qdrant.ConformanceTests/Filter/QdrantBasicFilterTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Qdrant.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace Qdrant.ConformanceTests.Filter; - -public class QdrantBasicFilterTests(QdrantBasicFilterTests.Fixture fixture) - : BasicFilterTests(fixture), IClassFixture -{ - public new class Fixture : BasicFilterTests.Fixture - { - public override TestStore TestStore => QdrantTestStore.NamedVectorsInstance; - } -} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/Filter/QdrantBasicQueryTests.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/Filter/QdrantBasicQueryTests.cs deleted file mode 100644 index 698c7ea9eba0..000000000000 --- a/dotnet/test/VectorData/Qdrant.ConformanceTests/Filter/QdrantBasicQueryTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Qdrant.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace Qdrant.ConformanceTests.Filter; - -public class QdrantBasicQueryTests(QdrantBasicQueryTests.Fixture fixture) - : BasicQueryTests(fixture), IClassFixture -{ - public new class Fixture : BasicQueryTests.QueryFixture - { - public override TestStore TestStore => QdrantTestStore.NamedVectorsInstance; - } -} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/ModelTests/QdrantBasicModelTests.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/ModelTests/QdrantBasicModelTests.cs new file mode 100644 index 000000000000..8804b3b12b12 --- /dev/null +++ b/dotnet/test/VectorData/Qdrant.ConformanceTests/ModelTests/QdrantBasicModelTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Qdrant.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Qdrant.ConformanceTests.ModelTests; + +public class QdrantBasicModelTests(QdrantBasicModelTests.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public override async Task GetAsync_with_filter_and_multiple_OrderBys() + { + var exception = await Assert.ThrowsAsync(base.GetAsync_with_filter_and_multiple_OrderBys); + + Assert.Equal("Qdrant does not support ordering by more than one property.", exception.Message); + } + + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => QdrantTestStore.NamedVectorsInstance; + } +} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/ModelTests/QdrantDynamicModelTests.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/ModelTests/QdrantDynamicModelTests.cs new file mode 100644 index 000000000000..95a5cb0fff8e --- /dev/null +++ b/dotnet/test/VectorData/Qdrant.ConformanceTests/ModelTests/QdrantDynamicModelTests.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Qdrant.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Qdrant.ConformanceTests.ModelTests; + +public class QdrantDynamicModelTests_NamedVectors(QdrantDynamicModelTests_NamedVectors.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public override async Task GetAsync_with_filter_and_multiple_OrderBys() + { + var exception = await Assert.ThrowsAsync(base.GetAsync_with_filter_and_multiple_OrderBys); + + Assert.Equal("Qdrant does not support ordering by more than one property.", exception.Message); + } + + public new class Fixture : DynamicModelTests.Fixture + { + public override TestStore TestStore => QdrantTestStore.NamedVectorsInstance; + } +} + +public class QdrantDynamicModelTests_UnnamedVector(QdrantDynamicModelTests_UnnamedVector.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public override async Task GetAsync_with_filter_and_multiple_OrderBys() + { + var exception = await Assert.ThrowsAsync(base.GetAsync_with_filter_and_multiple_OrderBys); + + Assert.Equal("Qdrant does not support ordering by more than one property.", exception.Message); + } + + public new class Fixture : DynamicModelTests.Fixture + { + public override TestStore TestStore => QdrantTestStore.UnnamedVectorInstance; + } +} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/ModelTests/QdrantNoDataModelTests.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/ModelTests/QdrantNoDataModelTests.cs new file mode 100644 index 000000000000..f31b64bb0a70 --- /dev/null +++ b/dotnet/test/VectorData/Qdrant.ConformanceTests/ModelTests/QdrantNoDataModelTests.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Qdrant.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Qdrant.ConformanceTests.ModelTests; + +public class QdrantNoDataModelTests_NamedVectors(QdrantNoDataModelTests_NamedVectors.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public new class Fixture : NoDataModelTests.Fixture + { + public override TestStore TestStore => QdrantTestStore.NamedVectorsInstance; + } +} + +public class QdrantNoDataModelTests_UnnamedVectors(QdrantNoDataModelTests_UnnamedVectors.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public new class Fixture : NoDataModelTests.Fixture + { + public override TestStore TestStore => QdrantTestStore.UnnamedVectorInstance; + } +} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/QdrantCollectionManagementTests.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/QdrantCollectionManagementTests.cs new file mode 100644 index 000000000000..98ee3a6937ca --- /dev/null +++ b/dotnet/test/VectorData/Qdrant.ConformanceTests/QdrantCollectionManagementTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Qdrant.ConformanceTests.Support; +using VectorData.ConformanceTests; +using Xunit; + +namespace Qdrant.ConformanceTests; + +public class QdrantCollectionManagementTests_NamedVectors(QdrantNamedVectorsFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} + +public class QdrantCollectionManagementTests_UnnamedVector(QdrantUnnamedVectorFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/QdrantFilterTests.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/QdrantFilterTests.cs new file mode 100644 index 000000000000..b894517282e3 --- /dev/null +++ b/dotnet/test/VectorData/Qdrant.ConformanceTests/QdrantFilterTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Qdrant.ConformanceTests.Support; +using VectorData.ConformanceTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Qdrant.ConformanceTests; + +public class QdrantFilterTests(QdrantFilterTests.Fixture fixture) + : FilterTests(fixture), IClassFixture +{ + public new class Fixture : FilterTests.Fixture + { + public override TestStore TestStore => QdrantTestStore.NamedVectorsInstance; + } +} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/Support/QdrantNamedDynamicDataModelFixture.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/Support/QdrantNamedDynamicDataModelFixture.cs deleted file mode 100644 index d3d5d8b5b3ae..000000000000 --- a/dotnet/test/VectorData/Qdrant.ConformanceTests/Support/QdrantNamedDynamicDataModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace Qdrant.ConformanceTests.Support; - -public class QdrantNamedDynamicDataModelFixture : DynamicDataModelFixture -{ - public override TestStore TestStore => QdrantTestStore.NamedVectorsInstance; -} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/Support/QdrantNamedSimpleModelFixture.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/Support/QdrantNamedSimpleModelFixture.cs deleted file mode 100644 index a7c2e9a68823..000000000000 --- a/dotnet/test/VectorData/Qdrant.ConformanceTests/Support/QdrantNamedSimpleModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace Qdrant.ConformanceTests.Support; - -public class QdrantNamedSimpleModelFixture : SimpleModelFixture -{ - public override TestStore TestStore => QdrantTestStore.NamedVectorsInstance; -} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/Support/QdrantUnnamedDynamicDataModelFixture.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/Support/QdrantUnnamedDynamicDataModelFixture.cs deleted file mode 100644 index 0d16adbcde11..000000000000 --- a/dotnet/test/VectorData/Qdrant.ConformanceTests/Support/QdrantUnnamedDynamicDataModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace Qdrant.ConformanceTests.Support; - -public class QdrantUnnamedDynamicDataModelFixture : DynamicDataModelFixture -{ - public override TestStore TestStore => QdrantTestStore.UnnamedVectorInstance; -} diff --git a/dotnet/test/VectorData/Qdrant.ConformanceTests/Support/QdrantUnnamedSimpleModelFixture.cs b/dotnet/test/VectorData/Qdrant.ConformanceTests/Support/QdrantUnnamedSimpleModelFixture.cs deleted file mode 100644 index 17a9f63feafd..000000000000 --- a/dotnet/test/VectorData/Qdrant.ConformanceTests/Support/QdrantUnnamedSimpleModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace Qdrant.ConformanceTests.Support; - -public class QdrantUnnamedSimpleModelFixture : SimpleModelFixture -{ - public override TestStore TestStore => QdrantTestStore.UnnamedVectorInstance; -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisHashSetDynamicDataModelConformanceTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisHashSetDynamicDataModelConformanceTests.cs deleted file mode 100644 index 873b24b46ae7..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisHashSetDynamicDataModelConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Redis.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace Redis.ConformanceTests.CRUD; - -public class RedisHashSetDynamicDataModelConformanceTests(RedisHashSetDynamicDataModelFixture fixture) - : DynamicDataModelConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisHashSetNoDataConformanceTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisHashSetNoDataConformanceTests.cs deleted file mode 100644 index 4417e786e257..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisHashSetNoDataConformanceTests.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Redis.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using VectorData.ConformanceTests.Xunit; -using Xunit; - -namespace Redis.ConformanceTests.CRUD; - -public class RedisHashSetNoDataConformanceTests(RedisHashSetNoDataConformanceTests.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - [ConditionalFact] - public override async Task GetAsyncReturnsInsertedRecord_WithoutVectors() - { - var expectedRecord = fixture.TestData[0]; - - // When using HashSets there is no way to distinguish between no fields being returned and - // the record not existing. - Assert.Null(await fixture.Collection.GetAsync(expectedRecord.Id, new() { IncludeVectors = false })); - } - - [ConditionalFact(Skip = "When using HashSets there is no way to distinguish between no fields being returned and the record not existing so this test isn't useful.")] - public override Task UpsertAsyncCanInsertNewRecord_WithoutVectors() - { - return base.UpsertAsyncCanInsertNewRecord_WithoutVectors(); - } - - [ConditionalFact(Skip = "When using HashSets there is no way to distinguish between no fields being returned and the record not existing so this test isn't useful.")] - public override Task UpsertAsyncCanUpdateExistingRecord_WithoutVectors() - { - return base.UpsertAsyncCanUpdateExistingRecord_WithoutVectors(); - } - - public new class Fixture : NoDataConformanceTests.Fixture - { - public override TestStore TestStore => RedisTestStore.HashSetInstance; - } -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisHashSetNoVectorConformanceTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisHashSetNoVectorConformanceTests.cs deleted file mode 100644 index a41964357bd2..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisHashSetNoVectorConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Redis.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace Redis.ConformanceTests.CRUD; - -public class RedisHashSetNoVectorConformanceTests(RedisHashSetNoVectorConformanceTests.Fixture fixture) - : NoVectorConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoVectorConformanceTests.Fixture - { - public override TestStore TestStore => RedisTestStore.HashSetInstance; - } -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisHashSetRecordConformanceTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisHashSetRecordConformanceTests.cs deleted file mode 100644 index e0cc681b8093..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisHashSetRecordConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Redis.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace Redis.ConformanceTests.CRUD; - -public class RedisHashSetRecordConformanceTests(RedisHashSetSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisJsonDynamicDataModelConformanceTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisJsonDynamicDataModelConformanceTests.cs deleted file mode 100644 index 6649912fb5d2..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisJsonDynamicDataModelConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Redis.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace Redis.ConformanceTests.CRUD; - -public class RedisJsonDynamicDataModelConformanceTests(RedisJsonDynamicDataModelFixture fixture) - : DynamicDataModelConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisJsonNoDataConformanceTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisJsonNoDataConformanceTests.cs deleted file mode 100644 index 236178638d07..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisJsonNoDataConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Redis.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace Redis.ConformanceTests.CRUD; - -public class RedisJsonNoDataConformanceTests(RedisJsonNoDataConformanceTests.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoDataConformanceTests.Fixture - { - public override TestStore TestStore => RedisTestStore.JsonInstance; - } -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisJsonNoVectorConformanceTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisJsonNoVectorConformanceTests.cs deleted file mode 100644 index 41c2df64e12d..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisJsonNoVectorConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Redis.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace Redis.ConformanceTests.CRUD; - -public class RedisJsonNoVectorConformanceTests(RedisJsonNoVectorConformanceTests.Fixture fixture) - : NoVectorConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoVectorConformanceTests.Fixture - { - public override TestStore TestStore => RedisTestStore.JsonInstance; - } -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisJsonRecordConformanceTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisJsonRecordConformanceTests.cs deleted file mode 100644 index c4801e41a203..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/CRUD/RedisJsonRecordConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Redis.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace Redis.ConformanceTests.CRUD; - -public class RedisJsonRecordConformanceTests(RedisJsonSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/Collections/RedisHashSetCollectionConformanceTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/Collections/RedisHashSetCollectionConformanceTests.cs deleted file mode 100644 index 7f3305db04d1..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/Collections/RedisHashSetCollectionConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Redis.ConformanceTests.Support; -using VectorData.ConformanceTests.Collections; -using Xunit; - -namespace Redis.ConformanceTests.Collections; - -public class RedisHashSetCollectionConformanceTests(RedisHashSetFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/Collections/RedisJsonCollectionConformanceTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/Collections/RedisJsonCollectionConformanceTests.cs deleted file mode 100644 index ffd7de57ef19..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/Collections/RedisJsonCollectionConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Redis.ConformanceTests.Support; -using VectorData.ConformanceTests.Collections; -using Xunit; - -namespace Redis.ConformanceTests.Collections; - -public class RedisJsonCollectionConformanceTests(RedisJsonFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/Filter/RedisBasicQueryTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/Filter/RedisBasicQueryTests.cs deleted file mode 100644 index 9cf5eac40e14..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/Filter/RedisBasicQueryTests.cs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.Extensions.VectorData; -using Microsoft.SemanticKernel.Connectors.Redis; -using Redis.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using Xunit; -using Xunit.Sdk; - -namespace Redis.ConformanceTests.Filter; - -public abstract class RedisBasicQueryTests(BasicQueryTests.QueryFixture fixture) - : BasicQueryTests(fixture) -{ - #region Equality with null - - public override Task Equal_with_null_reference_type() - => Assert.ThrowsAsync(() => base.Equal_with_null_reference_type()); - - public override Task Equal_with_null_captured() - => Assert.ThrowsAsync(() => base.Equal_with_null_captured()); - - public override Task NotEqual_with_null_reference_type() - => Assert.ThrowsAsync(() => base.Equal_with_null_reference_type()); - - public override Task NotEqual_with_null_captured() - => Assert.ThrowsAsync(() => base.NotEqual_with_null_captured()); - - public override Task Equal_int_property_with_null_nullable_int() - => Assert.ThrowsAsync(() => base.Equal_int_property_with_null_nullable_int()); - - #endregion - - #region Bool - - public override Task Bool() - => Assert.ThrowsAsync(() => base.Bool()); - - public override Task Not_over_bool() - => Assert.ThrowsAsync(() => base.Not_over_bool()); - - public override Task Bool_And_Bool() - => Assert.ThrowsAsync(() => base.Bool_And_Bool()); - - public override Task Bool_Or_Not_Bool() - => Assert.ThrowsAsync(() => base.Bool_Or_Not_Bool()); - - public override Task Not_over_bool_And_Comparison() - => Assert.ThrowsAsync(() => base.Not_over_bool_And_Comparison()); - - #endregion - - #region Contains - - public override Task Contains_over_inline_int_array() - => Assert.ThrowsAsync(() => base.Contains_over_inline_int_array()); - - public override Task Contains_over_inline_string_array() - => Assert.ThrowsAsync(() => base.Contains_over_inline_string_array()); - - public override Task Contains_over_inline_string_array_with_weird_chars() - => Assert.ThrowsAsync(() => base.Contains_over_inline_string_array_with_weird_chars()); - - public override Task Contains_over_captured_string_array() - => Assert.ThrowsAsync(() => base.Contains_over_captured_string_array()); - - #endregion -} - -public class RedisJsonCollectionBasicQueryTests(RedisJsonCollectionBasicQueryTests.Fixture fixture) - : RedisBasicQueryTests(fixture), IClassFixture -{ - public new class Fixture : BasicQueryTests.QueryFixture - { - public override TestStore TestStore => RedisTestStore.JsonInstance; - - public override string CollectionName => "JsonCollectionQueryTests"; - - public override string SpecialCharactersText -#if NET8_0_OR_GREATER - => base.SpecialCharactersText; -#else - // Redis client doesn't properly escape '"' on Full Framework. - => base.SpecialCharactersText.Replace("\"", ""); -#endif - - // Override to remove the bool property, which isn't (currently) supported on Redis/JSON - public override VectorStoreCollectionDefinition CreateRecordDefinition() - => new() - { - Properties = base.CreateRecordDefinition().Properties.Where(p => p.Type != typeof(bool)).ToList() - }; - - protected override VectorStoreCollection GetCollection() - => new RedisJsonCollection( - RedisTestStore.JsonInstance.Database, - this.CollectionName, - new() { Definition = this.CreateRecordDefinition() }); - } -} - -public class RedisHashSetCollectionBasicQueryTests(RedisHashSetCollectionBasicQueryTests.Fixture fixture) - : RedisBasicQueryTests(fixture), IClassFixture -{ - // Null values are not supported in Redis HashSet - public override Task Equal_with_null_reference_type() - => Assert.ThrowsAsync(() => base.Equal_with_null_reference_type()); - - public override Task Equal_with_null_captured() - => Assert.ThrowsAsync(() => base.Equal_with_null_captured()); - - public override Task NotEqual_with_null_reference_type() - => Assert.ThrowsAsync(() => base.NotEqual_with_null_reference_type()); - - public override Task NotEqual_with_null_captured() - => Assert.ThrowsAsync(() => base.NotEqual_with_null_captured()); - - // Array fields not supported on Redis HashSet - public override Task Contains_over_field_string_array() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_array()); - - public override Task Contains_over_field_string_List() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_List()); - - public override Task Contains_with_Enumerable_Contains() - => Assert.ThrowsAsync(() => base.Contains_with_Enumerable_Contains()); - -#if !NETFRAMEWORK - public override Task Contains_with_MemoryExtensions_Contains() - => Assert.ThrowsAsync(() => base.Contains_with_MemoryExtensions_Contains()); -#endif - -#if NET10_0_OR_GREATER - public override Task Contains_with_MemoryExtensions_Contains_with_null_comparer() - => Assert.ThrowsAsync(() => base.Contains_with_MemoryExtensions_Contains_with_null_comparer()); -#endif - - public new class Fixture : BasicQueryTests.QueryFixture - { - public override TestStore TestStore => RedisTestStore.HashSetInstance; - - public override string CollectionName => "HashSetCollectionQueryTests"; - - public override string SpecialCharactersText -#if NET8_0_OR_GREATER - => base.SpecialCharactersText; -#else - // Redis client doesn't properly escape '"' on Full Framework. - => base.SpecialCharactersText.Replace("\"", ""); -#endif - - // Override to remove the bool property, which isn't (currently) supported on Redis - public override VectorStoreCollectionDefinition CreateRecordDefinition() - => new() - { - Properties = base.CreateRecordDefinition().Properties.Where(p => - p.Type != typeof(bool) && - p.Type != typeof(string[]) && - p.Type != typeof(List)).ToList() - }; - - protected override VectorStoreCollection GetCollection() - => new RedisHashSetCollection( - RedisTestStore.HashSetInstance.Database, - this.CollectionName, - new() { Definition = this.CreateRecordDefinition() }); - - protected override List BuildTestData() - { - var testData = base.BuildTestData(); - - foreach (var record in testData) - { - // Null values are not supported in Redis hashsets - record.String ??= string.Empty; - } - - return testData; - } - } -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisHashSetBasicModelTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisHashSetBasicModelTests.cs new file mode 100644 index 000000000000..368d11be4e57 --- /dev/null +++ b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisHashSetBasicModelTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Redis.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Redis.ConformanceTests.ModelTests; + +public class RedisHashSetBasicModelTests(RedisHashSetBasicModelTests.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public override async Task GetAsync_with_filter_and_multiple_OrderBys() + { + var exception = await Assert.ThrowsAsync(base.GetAsync_with_filter_and_multiple_OrderBys); + + Assert.Equal("Redis does not support ordering by more than one property.", exception.Message); + } + + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => RedisTestStore.HashSetInstance; + } +} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisHashSetDynamicModelTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisHashSetDynamicModelTests.cs new file mode 100644 index 000000000000..a142f41f997d --- /dev/null +++ b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisHashSetDynamicModelTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Redis.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Redis.ConformanceTests.ModelTests; + +public class RedisHashSetDynamicModelTests(RedisHashSetDynamicModelTests.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public override async Task GetAsync_with_filter_and_multiple_OrderBys() + { + var exception = await Assert.ThrowsAsync(base.GetAsync_with_filter_and_multiple_OrderBys); + + Assert.Equal("Redis does not support ordering by more than one property.", exception.Message); + } + + public new class Fixture : DynamicModelTests.Fixture + { + public override TestStore TestStore => RedisTestStore.HashSetInstance; + } +} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisHashSetNoDataModelTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisHashSetNoDataModelTests.cs new file mode 100644 index 000000000000..7292b278b9a0 --- /dev/null +++ b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisHashSetNoDataModelTests.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Redis.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Redis.ConformanceTests.ModelTests; + +public class RedisHashSetNoDataModelTests(RedisHashSetNoDataModelTests.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public override async Task GetAsync_single_record(bool includeVectors) + { + var expectedRecord = fixture.TestData[0]; + + var received = await this.Collection.GetAsync(expectedRecord.Key, new() { IncludeVectors = includeVectors }); + + if (includeVectors) + { + expectedRecord.AssertEqual(received, includeVectors, fixture.TestStore.VectorsComparable); + } + else + { + // When vectors aren't included and there's no other data, we get null back. + Assert.Null(received); + } + } + + public new class Fixture : NoDataModelTests.Fixture + { + public override TestStore TestStore => RedisTestStore.HashSetInstance; + } +} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisHashSetNoVectorModelTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisHashSetNoVectorModelTests.cs new file mode 100644 index 000000000000..e9a39070d404 --- /dev/null +++ b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisHashSetNoVectorModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Redis.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Redis.ConformanceTests.ModelTests; + +public class RedisHashSetNoVectorModelTests(RedisHashSetNoVectorModelTests.Fixture fixture) + : NoVectorModelTests(fixture), IClassFixture +{ + public new class Fixture : NoVectorModelTests.Fixture + { + public override TestStore TestStore => RedisTestStore.HashSetInstance; + } +} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisJsonBasicModelTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisJsonBasicModelTests.cs new file mode 100644 index 000000000000..b2536bb3dca2 --- /dev/null +++ b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisJsonBasicModelTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Redis.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Redis.ConformanceTests.ModelTests; + +public class RedisJsonBasicModelTests(RedisJsonBasicModelTests.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public override async Task GetAsync_with_filter_and_multiple_OrderBys() + { + var exception = await Assert.ThrowsAsync(base.GetAsync_with_filter_and_multiple_OrderBys); + + Assert.Equal("Redis does not support ordering by more than one property.", exception.Message); + } + + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => RedisTestStore.JsonInstance; + } +} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisJsonDynamicModelTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisJsonDynamicModelTests.cs new file mode 100644 index 000000000000..ffba64c6e684 --- /dev/null +++ b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisJsonDynamicModelTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Redis.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Redis.ConformanceTests.ModelTests; + +public class RedisJsonDynamicModelTests(RedisJsonDynamicModelTests.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public override async Task GetAsync_with_filter_and_multiple_OrderBys() + { + var exception = await Assert.ThrowsAsync(base.GetAsync_with_filter_and_multiple_OrderBys); + + Assert.Equal("Redis does not support ordering by more than one property.", exception.Message); + } + + public new class Fixture : DynamicModelTests.Fixture + { + public override TestStore TestStore => RedisTestStore.JsonInstance; + } +} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisJsonNoDataModelTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisJsonNoDataModelTests.cs new file mode 100644 index 000000000000..289b00f60ea8 --- /dev/null +++ b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisJsonNoDataModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Redis.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Redis.ConformanceTests.ModelTests; + +public class RedisJsonNoDataModelTests(RedisJsonNoDataModelTests.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public new class Fixture : NoDataModelTests.Fixture + { + public override TestStore TestStore => RedisTestStore.JsonInstance; + } +} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisJsonNoVectorModelTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisJsonNoVectorModelTests.cs new file mode 100644 index 000000000000..079d15756b16 --- /dev/null +++ b/dotnet/test/VectorData/Redis.ConformanceTests/ModelTests/RedisJsonNoVectorModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Redis.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace Redis.ConformanceTests.ModelTests; + +public class RedisJsonNoVectorModelTests(RedisJsonNoVectorModelTests.Fixture fixture) + : NoVectorModelTests(fixture), IClassFixture +{ + public new class Fixture : NoVectorModelTests.Fixture + { + public override TestStore TestStore => RedisTestStore.JsonInstance; + } +} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/Filter/RedisBasicFilterTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/RedisFilterTests.cs similarity index 93% rename from dotnet/test/VectorData/Redis.ConformanceTests/Filter/RedisBasicFilterTests.cs rename to dotnet/test/VectorData/Redis.ConformanceTests/RedisFilterTests.cs index 0f144cdae20c..fd95cb072e26 100644 --- a/dotnet/test/VectorData/Redis.ConformanceTests/Filter/RedisBasicFilterTests.cs +++ b/dotnet/test/VectorData/Redis.ConformanceTests/RedisFilterTests.cs @@ -3,15 +3,15 @@ using Microsoft.Extensions.VectorData; using Microsoft.SemanticKernel.Connectors.Redis; using Redis.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; +using VectorData.ConformanceTests; using VectorData.ConformanceTests.Support; using Xunit; using Xunit.Sdk; -namespace Redis.ConformanceTests.Filter; +namespace Redis.ConformanceTests; -public abstract class RedisBasicFilterTests(BasicFilterTests.Fixture fixture) - : BasicFilterTests(fixture) +public abstract class RedisFilterTests(FilterTests.Fixture fixture) + : FilterTests(fixture) { #region Equality with null @@ -69,9 +69,9 @@ public override Task Contains_over_captured_string_array() } public class RedisJsonCollectionBasicFilterTests(RedisJsonCollectionBasicFilterTests.Fixture fixture) - : RedisBasicFilterTests(fixture), IClassFixture + : RedisFilterTests(fixture), IClassFixture { - public new class Fixture : BasicFilterTests.Fixture + public new class Fixture : FilterTests.Fixture { public override TestStore TestStore => RedisTestStore.JsonInstance; @@ -101,7 +101,7 @@ protected override VectorStoreCollection GetCollection() } public class RedisHashSetCollectionBasicFilterTests(RedisHashSetCollectionBasicFilterTests.Fixture fixture) - : RedisBasicFilterTests(fixture), IClassFixture + : RedisFilterTests(fixture), IClassFixture { // Null values are not supported in Redis HashSet public override Task Equal_with_null_reference_type() @@ -144,7 +144,7 @@ public override Task Legacy_AnyTagEqualTo_array() public override Task Legacy_AnyTagEqualTo_List() => Assert.ThrowsAsync(() => base.Legacy_AnyTagEqualTo_List()); - public new class Fixture : BasicFilterTests.Fixture + public new class Fixture : FilterTests.Fixture { public override TestStore TestStore => RedisTestStore.HashSetInstance; diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/RedisHashSetCollectionManagementTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/RedisHashSetCollectionManagementTests.cs new file mode 100644 index 000000000000..332654baedbb --- /dev/null +++ b/dotnet/test/VectorData/Redis.ConformanceTests/RedisHashSetCollectionManagementTests.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Redis.ConformanceTests.Support; +using VectorData.ConformanceTests; +using Xunit; + +namespace Redis.ConformanceTests; + +public class RedisHashSetCollectionManagementTests(RedisHashSetFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/RedisJsonCollectionManagementTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/RedisJsonCollectionManagementTests.cs new file mode 100644 index 000000000000..cb7ac0e8e91c --- /dev/null +++ b/dotnet/test/VectorData/Redis.ConformanceTests/RedisJsonCollectionManagementTests.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Redis.ConformanceTests.Support; +using VectorData.ConformanceTests; +using Xunit; + +namespace Redis.ConformanceTests; + +public class RedisJsonCollectionManagementTests(RedisJsonFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/RedisTestSuiteImplementationTests.cs b/dotnet/test/VectorData/Redis.ConformanceTests/RedisTestSuiteImplementationTests.cs index d2e5b409cb91..83006ecf8193 100644 --- a/dotnet/test/VectorData/Redis.ConformanceTests/RedisTestSuiteImplementationTests.cs +++ b/dotnet/test/VectorData/Redis.ConformanceTests/RedisTestSuiteImplementationTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. using VectorData.ConformanceTests; -using VectorData.ConformanceTests.CRUD; using VectorData.ConformanceTests.HybridSearch; using VectorData.ConformanceTests.VectorSearch; @@ -13,7 +12,6 @@ public class RedisTestSuiteImplementationTests : TestSuiteImplementationTests [ typeof(VectorSearchDistanceFunctionComplianceTests<>), typeof(VectorSearchWithFilterConformanceTests<>), - typeof(BatchConformanceTests<>), // Hybrid search not supported typeof(KeywordVectorizedHybridSearchComplianceTests<>) diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/Support/RedisHashSetDynamicDataModelFixture.cs b/dotnet/test/VectorData/Redis.ConformanceTests/Support/RedisHashSetDynamicDataModelFixture.cs deleted file mode 100644 index 6c49e3cc5b60..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/Support/RedisHashSetDynamicDataModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace Redis.ConformanceTests.Support; - -public class RedisHashSetDynamicDataModelFixture : DynamicDataModelFixture -{ - public override TestStore TestStore => RedisTestStore.HashSetInstance; -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/Support/RedisHashSetSimpleModelFixture.cs b/dotnet/test/VectorData/Redis.ConformanceTests/Support/RedisHashSetSimpleModelFixture.cs deleted file mode 100644 index b5927caa9b7d..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/Support/RedisHashSetSimpleModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace Redis.ConformanceTests.Support; - -public class RedisHashSetSimpleModelFixture : SimpleModelFixture -{ - public override TestStore TestStore => RedisTestStore.HashSetInstance; -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/Support/RedisJsonDynamicDataModelFixture.cs b/dotnet/test/VectorData/Redis.ConformanceTests/Support/RedisJsonDynamicDataModelFixture.cs deleted file mode 100644 index 9c0df8344e7a..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/Support/RedisJsonDynamicDataModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace Redis.ConformanceTests.Support; - -public class RedisJsonDynamicDataModelFixture : DynamicDataModelFixture -{ - public override TestStore TestStore => RedisTestStore.JsonInstance; -} diff --git a/dotnet/test/VectorData/Redis.ConformanceTests/Support/RedisJsonSimpleModelFixture.cs b/dotnet/test/VectorData/Redis.ConformanceTests/Support/RedisJsonSimpleModelFixture.cs deleted file mode 100644 index 923f355c947b..000000000000 --- a/dotnet/test/VectorData/Redis.ConformanceTests/Support/RedisJsonSimpleModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace Redis.ConformanceTests.Support; - -public class RedisJsonSimpleModelFixture : SimpleModelFixture -{ - public override TestStore TestStore => RedisTestStore.JsonInstance; -} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerBatchConformanceTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerBatchConformanceTests.cs deleted file mode 100644 index dac4d1b8fe53..000000000000 --- a/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerBatchConformanceTests.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.Extensions.VectorData; -using SqlServer.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Models; -using VectorData.ConformanceTests.Xunit; -using Xunit; - -namespace SqlServer.ConformanceTests.CRUD; - -public class SqlServerBatchConformanceTests(SqlServerSimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture -{ - private const int SqlServerMaxParameters = 2_100; - - [ConditionalFact] - public Task CanSplitBatchToAccountForMaxParameterLimit_WithVectors() - => this.CanSplitBatchToAccountForMaxParameterLimit(includeVectors: true); - - [ConditionalFact] - public Task CanSplitBatchToAccountForMaxParameterLimit_WithoutVectors() - => this.CanSplitBatchToAccountForMaxParameterLimit(includeVectors: false); - - private async Task CanSplitBatchToAccountForMaxParameterLimit(bool includeVectors) - { - var collection = fixture.Collection; - SimpleRecord[] inserted = Enumerable.Range(0, SqlServerMaxParameters + 1).Select(i => new SimpleRecord() - { - Id = fixture.GenerateNextKey(), - Number = 100 + i, - Text = i.ToString(), - Floats = Enumerable.Range(0, SimpleRecord.DimensionCount).Select(j => (float)(i + j)).ToArray() - }).ToArray(); - var keys = inserted.Select(record => record.Id).ToArray(); - - Assert.Empty(await collection.GetAsync(keys).ToArrayAsync()); - await collection.UpsertAsync(inserted); - - var received = await collection.GetAsync(keys, new() { IncludeVectors = includeVectors }).ToArrayAsync(); - foreach (var record in inserted) - { - record.AssertEqual(this.GetRecord(received, record.Id), includeVectors, fixture.TestStore.VectorsComparable); - } - - await collection.DeleteAsync(keys); - Assert.Empty(await collection.GetAsync(keys).ToArrayAsync()); - } - - [ConditionalFact] - public async Task UpsertBatchIsAtomic() - { - var collection = fixture.Collection; - SimpleRecord[] inserted = Enumerable.Range(0, SqlServerMaxParameters + 1).Select(i => new SimpleRecord() - { - // The last Id is set to NULL, so it must not be inserted and the whole batch should fail - Id = i < SqlServerMaxParameters ? fixture.GenerateNextKey() : null!, - Number = 100 + i, - Text = i.ToString(), - Floats = Enumerable.Range(0, SimpleRecord.DimensionCount).Select(j => (float)(i + j)).ToArray() - }).ToArray(); - - var keys = inserted.Select(record => record.Id).Where(key => key is not null).ToArray(); - Assert.Empty(await collection.GetAsync(keys).ToArrayAsync()); - - VectorStoreException ex = await Assert.ThrowsAsync(() => collection.UpsertAsync(inserted)); - Assert.Equal("UpsertBatch", ex.OperationName); - - var metadata = collection.GetService(typeof(VectorStoreCollectionMetadata)) as VectorStoreCollectionMetadata; - - Assert.NotNull(metadata?.CollectionName); - Assert.Equal(metadata.CollectionName, ex.CollectionName); - - // Make sure that no records were inserted! - Assert.Empty(await collection.GetAsync(keys).ToArrayAsync()); - } -} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerDynamicDataModelConformanceTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerDynamicDataModelConformanceTests.cs deleted file mode 100644 index aab43224b7cc..000000000000 --- a/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerDynamicDataModelConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using SqlServer.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace SqlServer.ConformanceTests.CRUD; - -public class SqlServerDynamicDataModelConformanceTests(SqlServerDynamicDataModelFixture fixture) - : DynamicDataModelConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerNoDataConformanceTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerNoDataConformanceTests.cs deleted file mode 100644 index 30507493fdea..000000000000 --- a/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerNoDataConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using SqlServer.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace SqlServer.ConformanceTests.CRUD; - -public class SqlServerNoDataConformanceTests(SqlServerNoDataConformanceTests.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoDataConformanceTests.Fixture - { - public override TestStore TestStore => SqlServerTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerNoVectorConformanceTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerNoVectorConformanceTests.cs deleted file mode 100644 index 5cecc8da7a8b..000000000000 --- a/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerNoVectorConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using SqlServer.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace SqlServer.ConformanceTests.CRUD; - -public class SqlServerNoVectorConformanceTests(SqlServerNoVectorConformanceTests.Fixture fixture) - : NoVectorConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoVectorConformanceTests.Fixture - { - public override TestStore TestStore => SqlServerTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerRecordConformanceTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerRecordConformanceTests.cs deleted file mode 100644 index 3c151e674f7b..000000000000 --- a/dotnet/test/VectorData/SqlServer.ConformanceTests/CRUD/SqlServerRecordConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using SqlServer.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace SqlServer.ConformanceTests.CRUD; - -public class SqlServerRecordConformanceTests(SqlServerSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/Collections/SqlServerCollectionConformanceTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/Collections/SqlServerCollectionConformanceTests.cs deleted file mode 100644 index d114f4ca6f31..000000000000 --- a/dotnet/test/VectorData/SqlServer.ConformanceTests/Collections/SqlServerCollectionConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using SqlServer.ConformanceTests.Support; -using VectorData.ConformanceTests.Collections; -using Xunit; - -namespace SqlServer.ConformanceTests.Collections; - -public class SqlServerCollectionConformanceTests(SqlServerFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/Filter/SqlServerBasicQueryTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/Filter/SqlServerBasicQueryTests.cs deleted file mode 100644 index b3c1acc13f60..000000000000 --- a/dotnet/test/VectorData/SqlServer.ConformanceTests/Filter/SqlServerBasicQueryTests.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.Extensions.VectorData; -using SqlServer.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using Xunit; -using Xunit.Sdk; - -namespace SqlServer.ConformanceTests.Filter; - -#pragma warning disable CS0252 // Possible unintended reference comparison; left hand side needs cast - -public class SqlServerBasicQueryTests(SqlServerBasicQueryTests.Fixture fixture) - : BasicQueryTests(fixture), IClassFixture -{ - public override async Task Not_over_Or() - { - // Test sends: WHERE (NOT (("Int" = 8) OR ("String" = 'foo'))) - // There's a NULL string in the database, and relational null semantics in conjunction with negation makes the default implementation fail. - await Assert.ThrowsAsync(() => base.Not_over_Or()); - - // Compensate by adding a null check: - await this.TestFilterAsync( - r => r.String != null && !(r.Int == 8 || r.String == "foo"), - r => r["String"] != null && !((int)r["Int"]! == 8 || r["String"] == "foo")); - } - - public override async Task NotEqual_with_string() - { - // As above, null semantics + negation - await Assert.ThrowsAsync(() => base.NotEqual_with_string()); - - await this.TestFilterAsync( - r => r.String != null && r.String != "foo", - r => r["String"] != null && r["String"] != "foo"); - } - - public override Task Contains_over_field_string_array() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_array()); - - public override Task Contains_over_field_string_List() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_List()); - - public override Task Contains_with_Enumerable_Contains() - => Assert.ThrowsAsync(() => base.Contains_with_Enumerable_Contains()); - -#if !NETFRAMEWORK - public override Task Contains_with_MemoryExtensions_Contains() - => Assert.ThrowsAsync(() => base.Contains_with_MemoryExtensions_Contains()); -#endif - -#if NET10_0_OR_GREATER - public override Task Contains_with_MemoryExtensions_Contains_with_null_comparer() - => Assert.ThrowsAsync(() => base.Contains_with_MemoryExtensions_Contains_with_null_comparer()); -#endif - - public new class Fixture : BasicQueryTests.QueryFixture - { - private static readonly string s_uniqueName = Guid.NewGuid().ToString(); - - public override TestStore TestStore => SqlServerTestStore.Instance; - - public override string CollectionName => s_uniqueName; - - // Override to remove the string collection properties, which aren't (currently) supported on SqlServer - public override VectorStoreCollectionDefinition CreateRecordDefinition() - => new() - { - Properties = base.CreateRecordDefinition().Properties.Where(p => p.Type != typeof(string[]) && p.Type != typeof(List)).ToList() - }; - } -} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/ModelTests/SqlServerBasicModelTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/ModelTests/SqlServerBasicModelTests.cs new file mode 100644 index 000000000000..2a4067defc01 --- /dev/null +++ b/dotnet/test/VectorData/SqlServer.ConformanceTests/ModelTests/SqlServerBasicModelTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Microsoft.Extensions.VectorData; +using SqlServer.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using VectorData.ConformanceTests.Xunit; +using Xunit; + +namespace SqlServer.ConformanceTests.ModelTests; + +public class SqlServerBasicModelTests(SqlServerBasicModelTests.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + private const int SqlServerMaxParameters = 2_100; + + [ConditionalFact] + private async Task Split_batches_to_account_for_max_parameter_limit() + { + var collection = fixture.Collection; + Record[] inserted = Enumerable.Range(0, SqlServerMaxParameters + 1).Select(i => new Record() + { + Key = fixture.GenerateNextKey(), + Number = 100 + i, + Text = i.ToString(), + Floats = Enumerable.Range(0, 3).Select(j => (float)(i + j)).ToArray() + }).ToArray(); + var keys = inserted.Select(record => record.Key).ToArray(); + + Assert.Empty(await collection.GetAsync(keys).ToArrayAsync()); + await collection.UpsertAsync(inserted); + + var received = await collection.GetAsync(keys).ToArrayAsync(); + foreach (var record in inserted) + { + record.AssertEqual( + received.Single(r => r.Key.Equals(record.Key, StringComparison.Ordinal)), + includeVectors: false, + fixture.TestStore.VectorsComparable); + } + + await collection.DeleteAsync(keys); + Assert.Empty(await collection.GetAsync(keys).ToArrayAsync()); + } + + [ConditionalFact] + public async Task Upsert_batch_is_atomic() + { + var collection = fixture.Collection; + Record[] inserted = Enumerable.Range(0, SqlServerMaxParameters + 1).Select(i => new Record() + { + // The last Key is set to NULL, so it must not be inserted and the whole batch should fail + Key = i < SqlServerMaxParameters ? fixture.GenerateNextKey() : null!, + Number = 100 + i, + Text = i.ToString(), + Floats = Enumerable.Range(0, 3).Select(j => (float)(i + j)).ToArray() + }).ToArray(); + + var keys = inserted.Select(record => record.Key).Where(key => key is not null).ToArray(); + Assert.Empty(await collection.GetAsync(keys).ToArrayAsync()); + + VectorStoreException ex = await Assert.ThrowsAsync(() => collection.UpsertAsync(inserted)); + Assert.Equal("UpsertBatch", ex.OperationName); + + var metadata = collection.GetService(typeof(VectorStoreCollectionMetadata)) as VectorStoreCollectionMetadata; + + Assert.NotNull(metadata?.CollectionName); + Assert.Equal(metadata.CollectionName, ex.CollectionName); + + // Make sure that no records were inserted! + Assert.Empty(await collection.GetAsync(keys).ToArrayAsync()); + } + + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => SqlServerTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/ModelTests/SqlServerDynamicModelTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/ModelTests/SqlServerDynamicModelTests.cs new file mode 100644 index 000000000000..038623e67e84 --- /dev/null +++ b/dotnet/test/VectorData/SqlServer.ConformanceTests/ModelTests/SqlServerDynamicModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using SqlServer.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace SqlServer.ConformanceTests.ModelTests; + +public class SqlServerDynamicModelTests(SqlServerDynamicModelTests.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public new class Fixture : DynamicModelTests.Fixture + { + public override TestStore TestStore => SqlServerTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/ModelTests/SqlServerNoDataModelTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/ModelTests/SqlServerNoDataModelTests.cs new file mode 100644 index 000000000000..6938f268e70c --- /dev/null +++ b/dotnet/test/VectorData/SqlServer.ConformanceTests/ModelTests/SqlServerNoDataModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using SqlServer.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace SqlServer.ConformanceTests.ModelTests; + +public class SqlServerNoDataModelTests(SqlServerNoDataModelTests.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public new class Fixture : NoDataModelTests.Fixture + { + public override TestStore TestStore => SqlServerTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/ModelTests/SqlServerNoVectorModelTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/ModelTests/SqlServerNoVectorModelTests.cs new file mode 100644 index 000000000000..5d8bc1bb7f1b --- /dev/null +++ b/dotnet/test/VectorData/SqlServer.ConformanceTests/ModelTests/SqlServerNoVectorModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using SqlServer.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace SqlServer.ConformanceTests.ModelTests; + +public class SqlServerNoVectorModelTests(SqlServerNoVectorModelTests.Fixture fixture) + : NoVectorModelTests(fixture), IClassFixture +{ + public new class Fixture : NoVectorModelTests.Fixture + { + public override TestStore TestStore => SqlServerTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/SqlServerCollectionManagementTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/SqlServerCollectionManagementTests.cs new file mode 100644 index 000000000000..5f1b9eca11fd --- /dev/null +++ b/dotnet/test/VectorData/SqlServer.ConformanceTests/SqlServerCollectionManagementTests.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. + +using SqlServer.ConformanceTests.Support; +using VectorData.ConformanceTests; +using Xunit; + +namespace SqlServer.ConformanceTests; + +public class SqlServerCollectionManagementTests(SqlServerFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/Filter/SqlServerBasicFilterTests.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/SqlServerFilterTests.cs similarity index 87% rename from dotnet/test/VectorData/SqlServer.ConformanceTests/Filter/SqlServerBasicFilterTests.cs rename to dotnet/test/VectorData/SqlServer.ConformanceTests/SqlServerFilterTests.cs index 92ce6163be1e..5f1b079d88a6 100644 --- a/dotnet/test/VectorData/SqlServer.ConformanceTests/Filter/SqlServerBasicFilterTests.cs +++ b/dotnet/test/VectorData/SqlServer.ConformanceTests/SqlServerFilterTests.cs @@ -1,17 +1,17 @@ // Copyright (c) Microsoft. All rights reserved. using SqlServer.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; +using VectorData.ConformanceTests; using VectorData.ConformanceTests.Support; using Xunit; using Xunit.Sdk; -namespace SqlServer.ConformanceTests.Filter; +namespace SqlServer.ConformanceTests; #pragma warning disable CS0252 // Possible unintended reference comparison; left hand side needs cast -public class SqlServerBasicFilterTests(SqlServerBasicFilterTests.Fixture fixture) - : BasicFilterTests(fixture), IClassFixture +public class SqlServerFilterTests(SqlServerFilterTests.Fixture fixture) + : FilterTests(fixture), IClassFixture { public override async Task Not_over_Or() { @@ -51,7 +51,7 @@ await this.TestFilterAsync( [Obsolete("Legacy filters are not supported")] public override Task Legacy_equality() => throw new NotSupportedException(); - public new class Fixture : BasicFilterTests.Fixture + public new class Fixture : FilterTests.Fixture { private static readonly string s_uniqueName = Guid.NewGuid().ToString(); diff --git a/dotnet/test/VectorData/SqlServer.ConformanceTests/Support/SqlServerDynamicDataModelFixture.cs b/dotnet/test/VectorData/SqlServer.ConformanceTests/Support/SqlServerDynamicDataModelFixture.cs deleted file mode 100644 index d63833931f91..000000000000 --- a/dotnet/test/VectorData/SqlServer.ConformanceTests/Support/SqlServerDynamicDataModelFixture.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace SqlServer.ConformanceTests.Support; - -public class SqlServerDynamicDataModelFixture : DynamicDataModelFixture -{ - public override TestStore TestStore => SqlServerTestStore.Instance; -} diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/CRUD/SqliteBatchConformanceTests.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/CRUD/SqliteBatchConformanceTests.cs deleted file mode 100644 index d32870ce6f56..000000000000 --- a/dotnet/test/VectorData/SqliteVec.ConformanceTests/CRUD/SqliteBatchConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using SqliteVec.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace SqliteVec.ConformanceTests.CRUD; - -public class SqliteBatchConformanceTests_string(SqliteSimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture> -{ -} - -public class SqliteBatchConformanceTests_long(SqliteSimpleModelFixture fixture) - : BatchConformanceTests(fixture), IClassFixture> -{ -} diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/CRUD/SqliteNoDataConformanceTests.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/CRUD/SqliteNoDataConformanceTests.cs deleted file mode 100644 index bcd9ad72171d..000000000000 --- a/dotnet/test/VectorData/SqliteVec.ConformanceTests/CRUD/SqliteNoDataConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using SqliteVec.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace SqliteVec.ConformanceTests.CRUD; - -public class SqliteNoDataConformanceTests(SqliteNoDataConformanceTests.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoDataConformanceTests.Fixture - { - public override TestStore TestStore => SqliteTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/CRUD/SqliteNoVectorConformanceTests.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/CRUD/SqliteNoVectorConformanceTests.cs deleted file mode 100644 index 184b8aa21ef3..000000000000 --- a/dotnet/test/VectorData/SqliteVec.ConformanceTests/CRUD/SqliteNoVectorConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using SqliteVec.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Xunit; - -namespace SqliteVec.ConformanceTests.CRUD; - -public class SqliteNoVectorConformanceTests(SqliteNoVectorConformanceTests.Fixture fixture) - : NoVectorConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoVectorConformanceTests.Fixture - { - public override TestStore TestStore => SqliteTestStore.Instance; - } -} diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/CRUD/SqliteRecordConformanceTests.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/CRUD/SqliteRecordConformanceTests.cs deleted file mode 100644 index 7960633ecb8a..000000000000 --- a/dotnet/test/VectorData/SqliteVec.ConformanceTests/CRUD/SqliteRecordConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using SqliteVec.ConformanceTests.Support; -using VectorData.ConformanceTests.CRUD; -using Xunit; - -namespace SqliteVec.ConformanceTests.CRUD; - -public class SqliteRecordConformanceTests_string(SqliteSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture> -{ -} - -public class SqliteRecordConformanceTests_long(SqliteSimpleModelFixture fixture) - : RecordConformanceTests(fixture), IClassFixture> -{ -} diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/Collections/SqliteCollectionConformanceTests.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/Collections/SqliteCollectionConformanceTests.cs deleted file mode 100644 index ac5c08ebdf19..000000000000 --- a/dotnet/test/VectorData/SqliteVec.ConformanceTests/Collections/SqliteCollectionConformanceTests.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using SqliteVec.ConformanceTests.Support; -using VectorData.ConformanceTests.Collections; -using Xunit; - -namespace SqliteVec.ConformanceTests.Collections; - -public class SqliteCollectionConformanceTests(SqliteFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/Filter/SqliteBasicQueryTests.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/Filter/SqliteBasicQueryTests.cs deleted file mode 100644 index 23989592a527..000000000000 --- a/dotnet/test/VectorData/SqliteVec.ConformanceTests/Filter/SqliteBasicQueryTests.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.Extensions.VectorData; -using SqliteVec.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using Xunit; -using Xunit.Sdk; - -namespace SqliteVec.ConformanceTests.Filter; - -#pragma warning disable CS0252 // Possible unintended reference comparison; left hand side needs cast - -public class SqliteBasicQueryTests(SqliteBasicQueryTests.Fixture fixture) - : BasicQueryTests(fixture), IClassFixture -{ - public override async Task Not_over_Or() - { - // Test sends: WHERE (NOT (("Int" = 8) OR ("String" = 'foo'))) - // There's a NULL string in the database, and relational null semantics in conjunction with negation makes the default implementation fail. - await Assert.ThrowsAsync(() => base.Not_over_Or()); - - // Compensate by adding a null check: - await this.TestFilterAsync( - r => r.String != null && !(r.Int == 8 || r.String == "foo"), - r => r["String"] != null && !((int)r["Int"]! == 8 || r["String"] == "foo")); - } - - public override async Task NotEqual_with_string() - { - // As above, null semantics + negation - await Assert.ThrowsAsync(() => base.NotEqual_with_string()); - - await this.TestFilterAsync( - r => r.String != null && r.String != "foo", - r => r["String"] != null && r["String"] != "foo"); - } - - // Array fields not (currently) supported on SQLite (see #10343) - public override Task Contains_over_field_string_array() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_array()); - - // List fields not (currently) supported on SQLite (see #10343) - public override Task Contains_over_field_string_List() - => Assert.ThrowsAsync(() => base.Contains_over_field_string_List()); - - public new class Fixture : BasicQueryTests.QueryFixture - { - public override TestStore TestStore => SqliteTestStore.Instance; - - // Override to remove the string array property, which isn't (currently) supported on SQLite - public override VectorStoreCollectionDefinition CreateRecordDefinition() - => new() - { - Properties = base.CreateRecordDefinition().Properties.Where(p => p.Type != typeof(string[]) && p.Type != typeof(List)).ToList() - }; - } -} diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/ModelTests/SqliteBasicModelTests.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/ModelTests/SqliteBasicModelTests.cs new file mode 100644 index 000000000000..b8307d9cf857 --- /dev/null +++ b/dotnet/test/VectorData/SqliteVec.ConformanceTests/ModelTests/SqliteBasicModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using SqliteVec.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace SqliteVec.ConformanceTests.ModelTests; + +public class SqliteBasicModelTests(SqliteBasicModelTests.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => SqliteTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/ModelTests/SqliteNoDataModelTests.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/ModelTests/SqliteNoDataModelTests.cs new file mode 100644 index 000000000000..914ef7459a1e --- /dev/null +++ b/dotnet/test/VectorData/SqliteVec.ConformanceTests/ModelTests/SqliteNoDataModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using SqliteVec.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace SqliteVec.ConformanceTests.ModelTests; + +public class SqliteNoDataModelTests(SqliteNoDataModelTests.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture +{ + public new class Fixture : NoDataModelTests.Fixture + { + public override TestStore TestStore => SqliteTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/ModelTests/SqliteNoVectorModelTests.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/ModelTests/SqliteNoVectorModelTests.cs new file mode 100644 index 000000000000..64e6ff9d4bfb --- /dev/null +++ b/dotnet/test/VectorData/SqliteVec.ConformanceTests/ModelTests/SqliteNoVectorModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using SqliteVec.ConformanceTests.Support; +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Xunit; + +namespace SqliteVec.ConformanceTests.ModelTests; + +public class SqliteNoVectorModelTests(SqliteNoVectorModelTests.Fixture fixture) + : NoVectorModelTests(fixture), IClassFixture +{ + public new class Fixture : NoVectorModelTests.Fixture + { + public override TestStore TestStore => SqliteTestStore.Instance; + } +} diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/SqliteCollectionManagementTests.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/SqliteCollectionManagementTests.cs new file mode 100644 index 000000000000..a3d0e036b30d --- /dev/null +++ b/dotnet/test/VectorData/SqliteVec.ConformanceTests/SqliteCollectionManagementTests.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. + +using SqliteVec.ConformanceTests.Support; +using VectorData.ConformanceTests; +using Xunit; + +namespace SqliteVec.ConformanceTests; + +public class SqliteCollectionManagementTests(SqliteFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/Filter/SqliteBasicFilterTests.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/SqliteFilterTests.cs similarity index 77% rename from dotnet/test/VectorData/SqliteVec.ConformanceTests/Filter/SqliteBasicFilterTests.cs rename to dotnet/test/VectorData/SqliteVec.ConformanceTests/SqliteFilterTests.cs index 0592877d1c39..d981a2a12998 100644 --- a/dotnet/test/VectorData/SqliteVec.ConformanceTests/Filter/SqliteBasicFilterTests.cs +++ b/dotnet/test/VectorData/SqliteVec.ConformanceTests/SqliteFilterTests.cs @@ -2,17 +2,17 @@ using Microsoft.Extensions.VectorData; using SqliteVec.ConformanceTests.Support; -using VectorData.ConformanceTests.Filter; +using VectorData.ConformanceTests; using VectorData.ConformanceTests.Support; using Xunit; using Xunit.Sdk; -namespace SqliteVec.ConformanceTests.Filter; +namespace SqliteVec.ConformanceTests; #pragma warning disable CS0252 // Possible unintended reference comparison; left hand side needs cast -public class SqliteBasicFilterTests(SqliteBasicFilterTests.Fixture fixture) - : BasicFilterTests(fixture), IClassFixture +public class SqliteFilterTests(SqliteFilterTests.Fixture fixture) + : FilterTests(fixture), IClassFixture { public override async Task Not_over_Or() { @@ -44,6 +44,16 @@ public override Task Contains_over_field_string_array() public override Task Contains_over_field_string_List() => Assert.ThrowsAsync(() => base.Contains_over_field_string_List()); + // List fields not (currently) supported on SQLite (see #10343) + public override Task Contains_with_Enumerable_Contains() + => Assert.ThrowsAsync(() => base.Contains_with_Enumerable_Contains()); + +#if !NETFRAMEWORK + // List fields not (currently) supported on SQLite (see #10343) + public override Task Contains_with_MemoryExtensions_Contains() + => Assert.ThrowsAsync(() => base.Contains_with_MemoryExtensions_Contains()); +#endif + // AnyTagEqualTo not (currently) supported on SQLite [Obsolete("Legacy filter support")] public override Task Legacy_AnyTagEqualTo_array() @@ -53,7 +63,7 @@ public override Task Legacy_AnyTagEqualTo_array() public override Task Legacy_AnyTagEqualTo_List() => Assert.ThrowsAsync(() => base.Legacy_AnyTagEqualTo_List()); - public new class Fixture : BasicFilterTests.Fixture + public new class Fixture : FilterTests.Fixture { public override TestStore TestStore => SqliteTestStore.Instance; diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/SqliteTestSuiteImplementationTests.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/SqliteTestSuiteImplementationTests.cs index 41f9669cc559..d117ffded6a6 100644 --- a/dotnet/test/VectorData/SqliteVec.ConformanceTests/SqliteTestSuiteImplementationTests.cs +++ b/dotnet/test/VectorData/SqliteVec.ConformanceTests/SqliteTestSuiteImplementationTests.cs @@ -1,8 +1,8 @@ // Copyright (c) Microsoft. All rights reserved. using VectorData.ConformanceTests; -using VectorData.ConformanceTests.CRUD; using VectorData.ConformanceTests.HybridSearch; +using VectorData.ConformanceTests.ModelTests; using VectorData.ConformanceTests.VectorSearch; namespace SqliteVec.ConformanceTests; @@ -12,7 +12,7 @@ public class SqliteTestSuiteImplementationTests : TestSuiteImplementationTests protected override ICollection IgnoredTestBases { get; } = [ typeof(VectorSearchDistanceFunctionComplianceTests<>), - typeof(DynamicDataModelConformanceTests<>), + typeof(DynamicModelTests<>), // Hybrid search not supported typeof(KeywordVectorizedHybridSearchComplianceTests<>) diff --git a/dotnet/test/VectorData/SqliteVec.ConformanceTests/Support/SqliteSimpleModelFixture.cs b/dotnet/test/VectorData/SqliteVec.ConformanceTests/Support/SqliteSimpleModelFixture.cs deleted file mode 100644 index b2ed18359001..000000000000 --- a/dotnet/test/VectorData/SqliteVec.ConformanceTests/Support/SqliteSimpleModelFixture.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; - -namespace SqliteVec.ConformanceTests.Support; - -public class SqliteSimpleModelFixture : SimpleModelFixture - where TKey : notnull -{ - public override TestStore TestStore => SqliteTestStore.Instance; -} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/BatchConformanceTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/BatchConformanceTests.cs deleted file mode 100644 index 3ae7fe402778..000000000000 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/BatchConformanceTests.cs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Models; -using VectorData.ConformanceTests.Support; -using VectorData.ConformanceTests.Xunit; -using Xunit; - -namespace VectorData.ConformanceTests.CRUD; - -public abstract class BatchConformanceTests(SimpleModelFixture fixture) where TKey : notnull -{ - [ConditionalFact] - public virtual async Task GetBatchAsyncThrowsArgumentNullExceptionForNullKeys() - { - ArgumentNullException ex = await Assert.ThrowsAsync(() => fixture.Collection.GetAsync(keys: null!).ToArrayAsync().AsTask()); - Assert.Equal("keys", ex.ParamName); - } - - [ConditionalFact] - public virtual async Task GetBatchAsyncDoesNotThrowForEmptyBatch() - { - Assert.Empty(await fixture.Collection.GetAsync([]).ToArrayAsync()); - } - - [ConditionalFact] - public virtual Task GetBatchAsync_WithVectors() - => this.GetBatchAsyncReturnsInsertedRecords(includeVectors: true); - - [ConditionalFact] - public virtual Task GetBatchAsync_WithoutVectors() - => this.GetBatchAsyncReturnsInsertedRecords(includeVectors: false); - - private async Task GetBatchAsyncReturnsInsertedRecords(bool includeVectors) - { - var expectedRecords = fixture.TestData.Take(2); // the last two records can get deleted by other tests - var ids = expectedRecords.Select(record => record.Id); - - var received = await fixture.Collection.GetAsync(ids, new() { IncludeVectors = includeVectors }).ToArrayAsync(); - - foreach (var record in expectedRecords) - { - record.AssertEqual(this.GetRecord(received, record.Id), includeVectors, fixture.TestStore.VectorsComparable); - } - } - - [ConditionalFact] - public virtual async Task UpsertBatchAsyncThrowsArgumentNullExceptionForNullBatch() - { - ArgumentNullException ex = await Assert.ThrowsAsync(() => fixture.Collection.UpsertAsync(records: null!)); - Assert.Equal("records", ex.ParamName); - } - - [ConditionalFact] - public virtual async Task UpsertBatchAsyncDoesNotThrowForEmptyBatch() - { - await fixture.Collection.UpsertAsync([]); - } - - [ConditionalFact] - public virtual async Task UpsertBatchAsyncCanInsertNewRecord() - { - var collection = fixture.Collection; - SimpleRecord[] inserted = Enumerable.Range(0, 10).Select(i => new SimpleRecord() - { - Id = fixture.GenerateNextKey(), - Number = 100 + i, - Text = i.ToString(), - Floats = Enumerable.Range(0, SimpleRecord.DimensionCount).Select(j => (float)(i + j)).ToArray() - }).ToArray(); - var keys = inserted.Select(record => record.Id).ToArray(); - - Assert.Empty(await collection.GetAsync(keys).ToArrayAsync()); - await collection.UpsertAsync(inserted); - - var received = await collection.GetAsync(keys, new() { IncludeVectors = true }).ToArrayAsync(); - foreach (var record in inserted) - { - record.AssertEqual(this.GetRecord(received, record.Id), includeVectors: true, fixture.TestStore.VectorsComparable); - } - } - - [ConditionalFact] - public virtual async Task UpsertBatchAsyncCanUpdateExistingRecords() - { - SimpleRecord[] inserted = Enumerable.Range(0, 10).Select(i => new SimpleRecord() - { - Id = fixture.GenerateNextKey(), - Number = 100 + i, - Text = i.ToString(), - Floats = Enumerable.Range(0, SimpleRecord.DimensionCount).Select(j => (float)(i + j)).ToArray() - }).ToArray(); - await fixture.Collection.UpsertAsync(inserted); - - SimpleRecord[] updated = inserted.Select(i => new SimpleRecord() - { - Id = i.Id, - Text = i.Text + "updated", - Number = i.Number + 200, - Floats = i.Floats - }).ToArray(); - - await fixture.Collection.UpsertAsync(updated); - } - - [ConditionalFact] - public virtual async Task UpsertCanBothInsertAndUpdateRecordsFromTheSameBatch() - { - SimpleRecord[] records = Enumerable.Range(0, 10).Select(i => new SimpleRecord() - { - Id = fixture.GenerateNextKey(), - Number = 100 + i, - Text = i.ToString(), - Floats = Enumerable.Range(0, SimpleRecord.DimensionCount).Select(j => (float)(i + j)).ToArray() - }).ToArray(); - - // We take first half of the records and insert them. - SimpleRecord[] firstHalf = records.Take(records.Length / 2).ToArray(); - await fixture.Collection.UpsertAsync(firstHalf); - - // Now we modify the first half of the records. - foreach (var record in firstHalf) - { - record.Text += "updated"; - record.Number += 200; - } - - // And now we upsert all the records (the first half is an update, the second is an insert). - await fixture.Collection.UpsertAsync(records); - } - - [ConditionalFact] - public virtual async Task DeleteBatchAsyncDoesNotThrowForEmptyBatch() - { - await fixture.Collection.DeleteAsync([]); - } - - [ConditionalFact] - public virtual async Task DeleteBatchAsyncThrowsArgumentNullExceptionForNullKeys() - { - ArgumentNullException ex = await Assert.ThrowsAsync(() => fixture.Collection.DeleteAsync(keys: null!)); - Assert.Equal("keys", ex.ParamName); - } - - [ConditionalFact] - public virtual async Task DeleteBatchAsyncDeletesTheRecords() - { - TKey[] idsToRemove = [fixture.TestData[2].Id, fixture.TestData[3].Id]; - - Assert.NotEmpty(await fixture.Collection.GetAsync(idsToRemove).ToArrayAsync()); - await fixture.Collection.DeleteAsync(idsToRemove); - Assert.Empty(await fixture.Collection.GetAsync(idsToRemove).ToArrayAsync()); - } - - // The order of records in the received array is not guaranteed - // to match the order of keys in the requested keys array. - protected SimpleRecord GetRecord(SimpleRecord[] received, TKey key) - => received.Single(r => r.Id!.Equals(key)); -} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/DynamicDataModelConformanceTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/DynamicDataModelConformanceTests.cs deleted file mode 100644 index 7a65c7c538ce..000000000000 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/DynamicDataModelConformanceTests.cs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Support; -using VectorData.ConformanceTests.Xunit; -using Xunit; - -namespace VectorData.ConformanceTests.CRUD; - -public abstract class DynamicDataModelConformanceTests(DynamicDataModelFixture fixture) - where TKey : notnull -{ - [ConditionalFact] - public virtual async Task GetAsyncThrowsArgumentNullExceptionForNullKey() - { - // Skip this test for value type keys - if (default(TKey) is not null) - { - return; - } - - ArgumentNullException ex = await Assert.ThrowsAsync(() => fixture.Collection.GetAsync((TKey)default!)); - Assert.Equal("key", ex.ParamName); - } - - [ConditionalFact] - public virtual async Task GetAsyncReturnsNullForNonExistingKey() - { - TKey key = fixture.GenerateNextKey(); - - Assert.Null(await fixture.Collection.GetAsync(key)); - } - - [ConditionalFact] - public virtual Task GetAsync_WithVectors() - => this.GetAsyncReturnsInsertedRecord(includeVectors: true); - - [ConditionalFact] - public virtual Task GetAsync_WithoutVectors() - => this.GetAsyncReturnsInsertedRecord(includeVectors: false); - - private async Task GetAsyncReturnsInsertedRecord(bool includeVectors) - { - var expectedRecord = fixture.TestData[0]; - - var received = await fixture.Collection.GetAsync( - (TKey)expectedRecord[DynamicDataModelFixture.KeyPropertyName]!, - new() { IncludeVectors = includeVectors }); - - AssertEquivalent(expectedRecord, received, includeVectors, fixture.TestStore.VectorsComparable); - } - - [ConditionalFact] - public virtual async Task UpsertAsyncCanInsertNewRecord() - { - var collection = fixture.Collection; - TKey expectedKey = fixture.GenerateNextKey(); - var inserted = new Dictionary - { - [DynamicDataModelFixture.KeyPropertyName] = expectedKey, - [DynamicDataModelFixture.StringPropertyName] = "some", - [DynamicDataModelFixture.IntegerPropertyName] = 123, - [DynamicDataModelFixture.EmbeddingPropertyName] = new ReadOnlyMemory(Enumerable.Repeat(0.1f, DynamicDataModelFixture.DimensionCount).ToArray()) - }; - - Assert.Null(await collection.GetAsync(expectedKey)); - await collection.UpsertAsync(inserted); - - var received = await collection.GetAsync(expectedKey, new() { IncludeVectors = true }); - AssertEquivalent(inserted, received, includeVectors: true, fixture.TestStore.VectorsComparable); - } - - [ConditionalFact] - public virtual async Task UpsertAsyncCanUpdateExistingRecord() - { - var collection = fixture.Collection; - var existingRecord = fixture.TestData[1]; - var updated = new Dictionary - { - [DynamicDataModelFixture.KeyPropertyName] = existingRecord[DynamicDataModelFixture.KeyPropertyName], - [DynamicDataModelFixture.StringPropertyName] = "different", - [DynamicDataModelFixture.IntegerPropertyName] = 456, - [DynamicDataModelFixture.EmbeddingPropertyName] = new ReadOnlyMemory(Enumerable.Repeat(0.7f, DynamicDataModelFixture.DimensionCount).ToArray()) - }; - - Assert.NotNull(await collection.GetAsync((TKey)existingRecord[DynamicDataModelFixture.KeyPropertyName]!)); - await collection.UpsertAsync(updated); - - var received = await collection.GetAsync((TKey)existingRecord[DynamicDataModelFixture.KeyPropertyName]!, new() { IncludeVectors = true }); - AssertEquivalent(updated, received, includeVectors: true, fixture.TestStore.VectorsComparable); - } - - [ConditionalFact] - public virtual async Task DeleteAsyncDoesNotThrowForNonExistingKey() - { - TKey key = fixture.GenerateNextKey(); - - await fixture.Collection.DeleteAsync(key); - } - - [ConditionalFact] - public async Task DeleteAsyncDeletesTheRecord() - { - var recordToRemove = fixture.TestData[2]; - - Assert.NotNull(await fixture.Collection.GetAsync((TKey)recordToRemove[DynamicDataModelFixture.KeyPropertyName]!)); - await fixture.Collection.DeleteAsync((TKey)recordToRemove[DynamicDataModelFixture.KeyPropertyName]!); - Assert.Null(await fixture.Collection.GetAsync((TKey)recordToRemove[DynamicDataModelFixture.KeyPropertyName]!)); - } - - protected static void AssertEquivalent(Dictionary expected, Dictionary? actual, bool includeVectors, bool compareVectors) - { - Assert.NotNull(actual); - Assert.Equal(expected[DynamicDataModelFixture.KeyPropertyName], actual[DynamicDataModelFixture.KeyPropertyName]); - - Assert.Equal(expected[DynamicDataModelFixture.StringPropertyName], actual[DynamicDataModelFixture.StringPropertyName]); - Assert.Equal(expected[DynamicDataModelFixture.IntegerPropertyName], actual[DynamicDataModelFixture.IntegerPropertyName]); - - if (includeVectors) - { - Assert.Equal( - ((ReadOnlyMemory)expected[DynamicDataModelFixture.EmbeddingPropertyName]!).Length, - ((ReadOnlyMemory)actual[DynamicDataModelFixture.EmbeddingPropertyName]!).Length); - - if (compareVectors) - { - Assert.Equal( - ((ReadOnlyMemory)expected[DynamicDataModelFixture.EmbeddingPropertyName]!).ToArray(), - ((ReadOnlyMemory)actual[DynamicDataModelFixture.EmbeddingPropertyName]!).ToArray()); - } - } - else - { - Assert.False(actual.ContainsKey(DynamicDataModelFixture.EmbeddingPropertyName)); - } - } -} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/NoDataConformanceTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/NoDataConformanceTests.cs deleted file mode 100644 index 27c128041a68..000000000000 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/NoDataConformanceTests.cs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.Extensions.VectorData; -using VectorData.ConformanceTests.Support; -using VectorData.ConformanceTests.Xunit; -using Xunit; - -namespace VectorData.ConformanceTests.CRUD; - -/// -/// Tests CRUD operations using a model without data fields. -/// -public class NoDataConformanceTests(NoDataConformanceTests.Fixture fixture) where TKey : notnull -{ - [ConditionalFact] - public virtual Task GetAsyncReturnsInsertedRecord_WithVectors() - => this.GetAsyncReturnsInsertedRecord(includeVectors: true); - - [ConditionalFact] - public virtual Task GetAsyncReturnsInsertedRecord_WithoutVectors() - => this.GetAsyncReturnsInsertedRecord(includeVectors: false); - - private async Task GetAsyncReturnsInsertedRecord(bool includeVectors) - { - var expectedRecord = fixture.TestData[0]; - - var received = await fixture.Collection.GetAsync(expectedRecord.Id, new() { IncludeVectors = includeVectors }); - - expectedRecord.AssertEqual(received, includeVectors, fixture.TestStore.VectorsComparable); - } - - [ConditionalFact] - public virtual Task UpsertAsyncCanInsertNewRecord_WithVectors() - => this.UpsertAsyncCanInsertNewRecord(includeVectors: true); - - [ConditionalFact] - public virtual Task UpsertAsyncCanInsertNewRecord_WithoutVectors() - => this.UpsertAsyncCanInsertNewRecord(includeVectors: false); - - private async Task UpsertAsyncCanInsertNewRecord(bool includeVectors) - { - var collection = fixture.Collection; - TKey expectedKey = fixture.GenerateNextKey(); - NoDataRecord inserted = new() - { - Id = expectedKey, - Floats = new ReadOnlyMemory(Enumerable.Repeat(0.1f, NoDataRecord.DimensionCount).ToArray()) - }; - - Assert.Null(await collection.GetAsync(expectedKey)); - await collection.UpsertAsync(inserted); - - var received = await collection.GetAsync(expectedKey, new() { IncludeVectors = includeVectors }); - inserted.AssertEqual(received, includeVectors, fixture.TestStore.VectorsComparable); - } - - [ConditionalFact] - public virtual Task UpsertAsyncCanUpdateExistingRecord_WithVectors() - => this.UpsertAsyncCanUpdateExistingRecord(includeVectors: true); - - [ConditionalFact] - public virtual Task UpsertAsyncCanUpdateExistingRecord_WithoutVectors() - => this.UpsertAsyncCanUpdateExistingRecord(includeVectors: false); - - private async Task UpsertAsyncCanUpdateExistingRecord(bool includeVectors) - { - var collection = fixture.Collection; - var existingRecord = fixture.TestData[1]; - NoDataRecord updated = new() - { - Id = existingRecord.Id, - Floats = new ReadOnlyMemory(Enumerable.Repeat(0.25f, NoDataRecord.DimensionCount).ToArray()) - }; - - Assert.NotNull(await collection.GetAsync(existingRecord.Id, new() { IncludeVectors = true })); - await collection.UpsertAsync(updated); - - var received = await collection.GetAsync(existingRecord.Id, new() { IncludeVectors = includeVectors }); - updated.AssertEqual(received, includeVectors, fixture.TestStore.VectorsComparable); - } - - [ConditionalFact] - public virtual async Task DeleteAsyncDeletesTheRecord() - { - var recordToRemove = fixture.TestData[2]; - - Assert.NotNull(await fixture.Collection.GetAsync(recordToRemove.Id, new() { IncludeVectors = true })); - await fixture.Collection.DeleteAsync(recordToRemove.Id); - Assert.Null(await fixture.Collection.GetAsync(recordToRemove.Id)); - } - - /// - /// This class is for testing databases that support having no data fields. - /// - public sealed class NoDataRecord - { - public const int DimensionCount = 3; - - [VectorStoreKey(StorageName = "key")] - public TKey Id { get; set; } = default!; - - [VectorStoreVector(DimensionCount, StorageName = "embedding")] - public ReadOnlyMemory Floats { get; set; } - - public void AssertEqual(NoDataRecord? other, bool includeVectors, bool compareVectors) - { - Assert.NotNull(other); - Assert.Equal(this.Id, other.Id); - - if (includeVectors) - { - Assert.Equal(this.Floats.Span.Length, other.Floats.Span.Length); - - if (compareVectors) - { - Assert.True(this.Floats.Span.SequenceEqual(other.Floats.Span)); - } - } - } - } - - /// - /// Provides data and configuration for a model without data fields. - /// - public abstract class Fixture : VectorStoreCollectionFixture - { - protected override List BuildTestData() => - [ - new() - { - Id = this.GenerateNextKey(), - Floats = new ReadOnlyMemory(Enumerable.Repeat(0.1f, NoDataRecord.DimensionCount).ToArray()) - }, - new() - { - Id = this.GenerateNextKey(), - Floats = new ReadOnlyMemory(Enumerable.Repeat(0.2f, NoDataRecord.DimensionCount).ToArray()) - }, - new() - { - Id = this.GenerateNextKey(), - Floats = new ReadOnlyMemory(Enumerable.Repeat(0.3f, NoDataRecord.DimensionCount).ToArray()) - }, - new() - { - Id = this.GenerateNextKey(), - Floats = new ReadOnlyMemory(Enumerable.Repeat(0.4f, NoDataRecord.DimensionCount).ToArray()) - } - ]; - - public override VectorStoreCollectionDefinition CreateRecordDefinition() - => new() - { - Properties = - [ - new VectorStoreKeyProperty(nameof(NoDataRecord.Id), typeof(TKey)) { StorageName = "key" }, - new VectorStoreVectorProperty(nameof(NoDataRecord.Floats), typeof(ReadOnlyMemory), NoDataRecord.DimensionCount) - { - StorageName = "embedding", - IndexKind = this.IndexKind, - } - ] - }; - - protected override async Task WaitForDataAsync() - { - for (var i = 0; i < 20; i++) - { - var getOptions = new RecordRetrievalOptions { IncludeVectors = true }; - var results = await this.Collection.GetAsync([this.TestData[0].Id, this.TestData[1].Id, this.TestData[2].Id, this.TestData[3].Id], getOptions).ToArrayAsync(); - if (results.Length == 4 && results.All(r => r != null)) - { - return; - } - - await Task.Delay(TimeSpan.FromMilliseconds(100)); - } - - throw new InvalidOperationException("Data did not appear in the collection within the expected time."); - } - } -} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/NoVectorConformanceTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/NoVectorConformanceTests.cs deleted file mode 100644 index 3e71d0cf5825..000000000000 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/NoVectorConformanceTests.cs +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.Extensions.VectorData; -using VectorData.ConformanceTests.Support; -using VectorData.ConformanceTests.Xunit; -using Xunit; - -namespace VectorData.ConformanceTests.CRUD; - -/// -/// Tests CRUD operations using a model without a vector. -/// This is only supported by a subset of databases so only extend if applicable for your database. -/// -public class NoVectorConformanceTests(NoVectorConformanceTests.Fixture fixture) where TKey : notnull -{ - [ConditionalFact] - public Task GetAsyncReturnsInsertedRecord_WithVectors() - => this.GetAsyncReturnsInsertedRecord(includeVectors: true); - - [ConditionalFact] - public Task GetAsyncReturnsInsertedRecord_WithoutVectors() - => this.GetAsyncReturnsInsertedRecord(includeVectors: false); - - private async Task GetAsyncReturnsInsertedRecord(bool includeVectors) - { - var expectedRecord = fixture.TestData[0]; - - var received = await fixture.Collection.GetAsync(expectedRecord.Id, new() { IncludeVectors = includeVectors }); - - expectedRecord.AssertEqual(received); - } - - [ConditionalFact] - public Task UpsertAsyncCanInsertNewRecord_WithVectors() - => this.UpsertAsyncCanInsertNewRecord(includeVectors: true); - - [ConditionalFact] - public Task UpsertAsyncCanInsertNewRecord_WithoutVectors() - => this.UpsertAsyncCanInsertNewRecord(includeVectors: false); - - private async Task UpsertAsyncCanInsertNewRecord(bool includeVectors) - { - var collection = fixture.Collection; - TKey expectedKey = fixture.GenerateNextKey(); - NoVectorRecord inserted = new() - { - Id = expectedKey, - Text = "some" - }; - - Assert.Null(await collection.GetAsync(expectedKey)); - await collection.UpsertAsync(inserted); - - var received = await collection.GetAsync(expectedKey, new() { IncludeVectors = includeVectors }); - inserted.AssertEqual(received); - } - - [ConditionalFact] - public Task UpsertAsyncCanUpdateExistingRecord_WithVectors() - => this.UpsertAsyncCanUpdateExistingRecord(includeVectors: true); - - [ConditionalFact] - public Task UpsertAsyncCanUpdateExistingRecord__WithoutVectors() - => this.UpsertAsyncCanUpdateExistingRecord(includeVectors: false); - - private async Task UpsertAsyncCanUpdateExistingRecord(bool includeVectors) - { - var collection = fixture.Collection; - var existingRecord = fixture.TestData[1]; - NoVectorRecord updated = new() - { - Id = existingRecord.Id, - Text = "updated" - }; - - Assert.NotNull(await collection.GetAsync(existingRecord.Id)); - await collection.UpsertAsync(updated); - - var received = await collection.GetAsync(existingRecord.Id, new() { IncludeVectors = includeVectors }); - updated.AssertEqual(received); - } - - [ConditionalFact] - public async Task DeleteAsyncDeletesTheRecord() - { - var recordToRemove = fixture.TestData[2]; - - Assert.NotNull(await fixture.Collection.GetAsync(recordToRemove.Id)); - await fixture.Collection.DeleteAsync(recordToRemove.Id); - Assert.Null(await fixture.Collection.GetAsync(recordToRemove.Id)); - } - - /// - /// This class is for testing databases that support having no vector. - /// Not all DBs support this. - /// - public sealed class NoVectorRecord - { - public const int DimensionCount = 3; - - [VectorStoreKey(StorageName = "key")] - public TKey Id { get; set; } = default!; - - [VectorStoreData(StorageName = "text")] - public string? Text { get; set; } - - public void AssertEqual(NoVectorRecord? other) - { - Assert.NotNull(other); - Assert.Equal(this.Id, other.Id); - Assert.Equal(this.Text, other.Text); - } - } - - /// - /// Provides data and configuration for a model without a vector, which is supported by some connectors. - /// - public abstract class Fixture : VectorStoreCollectionFixture - { - protected override List BuildTestData() => - [ - new() - { - Id = this.GenerateNextKey(), - Text = "UsedByGetTests", - }, - new() - { - Id = this.GenerateNextKey(), - Text = "UsedByUpdateTests", - }, - new() - { - Id = this.GenerateNextKey(), - Text = "UsedByDeleteTests", - }, - new() - { - Id = this.GenerateNextKey(), - Text = "UsedByDeleteBatchTests", - } - ]; - - public override VectorStoreCollectionDefinition CreateRecordDefinition() - => new() - { - Properties = - [ - new VectorStoreKeyProperty(nameof(NoVectorRecord.Id), typeof(TKey)) { StorageName = "key" }, - new VectorStoreDataProperty(nameof(NoVectorRecord.Text), typeof(string)) { IsIndexed = true, StorageName = "text" }, - ] - }; - - protected override async Task WaitForDataAsync() - { - for (var i = 0; i < 20; i++) - { - var results = await this.Collection.GetAsync([this.TestData[0].Id, this.TestData[1].Id, this.TestData[2].Id, this.TestData[3].Id]).ToArrayAsync(); - if (results.Length == 4 && results.All(r => r != null)) - { - return; - } - - await Task.Delay(TimeSpan.FromMilliseconds(100)); - } - - throw new InvalidOperationException("Data did not appear in the collection within the expected time."); - } - } -} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/RecordConformanceTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/RecordConformanceTests.cs deleted file mode 100644 index 0f41b93ccc4c..000000000000 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/CRUD/RecordConformanceTests.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Models; -using VectorData.ConformanceTests.Support; -using VectorData.ConformanceTests.Xunit; -using Xunit; - -namespace VectorData.ConformanceTests.CRUD; - -public class RecordConformanceTests(SimpleModelFixture fixture) where TKey : notnull -{ - [ConditionalFact] - public virtual async Task GetAsyncThrowsArgumentNullExceptionForNullKey() - { - // Skip this test for value type keys - if (default(TKey) is not null) - { - return; - } - - ArgumentNullException ex = await Assert.ThrowsAsync(() => fixture.Collection.GetAsync((TKey)default!)); - Assert.Equal("key", ex.ParamName); - } - - [ConditionalFact] - public virtual async Task GetAsyncReturnsNullForNonExistingKey() - { - TKey key = fixture.GenerateNextKey(); - - Assert.Null(await fixture.Collection.GetAsync(key)); - } - - [ConditionalFact] - public virtual Task GetAsync_WithVectors() - => this.GetAsyncReturnsInsertedRecord(includeVectors: true); - - [ConditionalFact] - public virtual Task GetAsync_WithoutVectors() - => this.GetAsyncReturnsInsertedRecord(includeVectors: false); - - private async Task GetAsyncReturnsInsertedRecord(bool includeVectors) - { - var expectedRecord = fixture.TestData[0]; - - var received = await fixture.Collection.GetAsync(expectedRecord.Id, new() { IncludeVectors = includeVectors }); - - expectedRecord.AssertEqual(received, includeVectors, fixture.TestStore.VectorsComparable); - } - - [ConditionalFact] - public virtual async Task UpsertAsyncCanInsertNewRecord() - { - var collection = fixture.Collection; - TKey expectedKey = fixture.GenerateNextKey(); - SimpleRecord inserted = new() - { - Id = expectedKey, - Text = "some", - Number = 123, - Floats = new ReadOnlyMemory(Enumerable.Repeat(0.1f, SimpleRecord.DimensionCount).ToArray()) - }; - - Assert.Null(await collection.GetAsync(expectedKey)); - await collection.UpsertAsync(inserted); - - var received = await collection.GetAsync(expectedKey, new() { IncludeVectors = true }); - inserted.AssertEqual(received, includeVectors: true, fixture.TestStore.VectorsComparable); - } - - [ConditionalFact] - public virtual async Task UpsertAsyncCanUpdateExistingRecord() - { - var collection = fixture.Collection; - var existingRecord = fixture.TestData[1]; - SimpleRecord updated = new() - { - Id = existingRecord.Id, - Text = "updated", - Number = 456, - Floats = new ReadOnlyMemory(Enumerable.Repeat(0.25f, SimpleRecord.DimensionCount).ToArray()) - }; - - Assert.NotNull(await collection.GetAsync(existingRecord.Id)); - await collection.UpsertAsync(updated); - - var received = await collection.GetAsync(existingRecord.Id, new() { IncludeVectors = true }); - updated.AssertEqual(received, includeVectors: true, fixture.TestStore.VectorsComparable); - } - - [ConditionalFact] - public virtual async Task DeleteAsyncDoesNotThrowForNonExistingKey() - { - TKey key = fixture.GenerateNextKey(); - - await fixture.Collection.DeleteAsync(key); - } - - [ConditionalFact] - public virtual async Task DeleteAsyncDeletesTheRecord() - { - var recordToRemove = fixture.TestData[2]; - - Assert.NotNull(await fixture.Collection.GetAsync(recordToRemove.Id)); - await fixture.Collection.DeleteAsync(recordToRemove.Id); - Assert.Null(await fixture.Collection.GetAsync(recordToRemove.Id)); - } -} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/Collections/CollectionConformanceTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/CollectionManagementTests.cs similarity index 95% rename from dotnet/test/VectorData/VectorData.ConformanceTests/Collections/CollectionConformanceTests.cs rename to dotnet/test/VectorData/VectorData.ConformanceTests/CollectionManagementTests.cs index c7eb4f7ac4ca..56a53797a117 100644 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/Collections/CollectionConformanceTests.cs +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/CollectionManagementTests.cs @@ -6,9 +6,9 @@ using VectorData.ConformanceTests.Xunit; using Xunit; -namespace VectorData.ConformanceTests.Collections; +namespace VectorData.ConformanceTests; -public abstract class CollectionConformanceTests(VectorStoreFixture fixture) : IAsyncLifetime +public abstract class CollectionManagementTests(VectorStoreFixture fixture) : IAsyncLifetime where TKey : notnull { public Task InitializeAsync() @@ -97,7 +97,7 @@ public virtual VectorStoreCollectionDefinition CreateRecordDefinition() { Properties = [ - new VectorStoreKeyProperty(nameof(SimpleRecord.Id), typeof(TKey)) { StorageName = "key" }, + new VectorStoreKeyProperty(nameof(SimpleRecord.Key), typeof(TKey)) { StorageName = "key" }, new VectorStoreDataProperty(nameof(SimpleRecord.Text), typeof(string)) { StorageName = "text" }, new VectorStoreDataProperty(nameof(SimpleRecord.Number), typeof(int)) { StorageName = "number" }, new VectorStoreVectorProperty(nameof(SimpleRecord.Floats), typeof(ReadOnlyMemory), 10) { IndexKind = fixture.TestStore.DefaultIndexKind } diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/DataTypeTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/DataTypeTests.cs index a17c95f28c43..e693f492f137 100644 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/DataTypeTests.cs +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/DataTypeTests.cs @@ -551,9 +551,8 @@ public virtual IList GetDataProperties() public abstract class DataTypeTests() where TKey : notnull { - public class RecordBase + public class RecordBase : TestRecord { - public TKey Key { get; set; } = default!; public float[] Vector { get; set; } = default!; } diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/EmbeddingGenerationTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/EmbeddingGenerationTests.cs index 60b562d60d6b..276dcafe1eff 100644 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/EmbeddingGenerationTests.cs +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/EmbeddingGenerationTests.cs @@ -340,9 +340,8 @@ public virtual async Task GetAsync_enumerable_with_IncludeVectors_throws() #region Support - public class Record + public class Record : TestRecord { - public TKey Key { get; set; } = default!; public string? Embedding { get; set; } public int Counter { get; set; } @@ -373,9 +372,8 @@ public class RecordWithCustomerVectorProperty public string? Text { get; set; } } - public class RecordWithRomOfFloatVectorProperty + public class RecordWithRomOfFloatVectorProperty : TestRecord { - public TKey Key { get; set; } = default!; public ReadOnlyMemory Embedding { get; set; } public int Counter { get; set; } diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/Filter/BasicQueryTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/Filter/BasicQueryTests.cs deleted file mode 100644 index 9bdf37950e79..000000000000 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/Filter/BasicQueryTests.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System.Linq.Expressions; - -namespace VectorData.ConformanceTests.Filter; - -public abstract class BasicQueryTests(BasicQueryTests.QueryFixture fixture) - : BasicFilterTests(fixture) where TKey : notnull -{ - protected override async Task> GetRecords(Expression> filter, int top, ReadOnlyMemory vector) - => (await fixture.Collection.GetAsync(filter, top).ToListAsync()).OrderBy(r => r.Key).ToList(); - - protected override async Task>> GetDynamicRecords(Expression, bool>> dynamicFilter, int top, ReadOnlyMemory vector) - => (await fixture.DynamicCollection.GetAsync(dynamicFilter, top).ToListAsync()).OrderBy(r => r[nameof(FilterRecord.Key)]!).ToList(); - - [Obsolete("Not used by derived types")] - public sealed override Task Legacy_And() => Task.CompletedTask; - - [Obsolete("Not used by derived types")] - public sealed override Task Legacy_equality() => Task.CompletedTask; - - [Obsolete("Not used by derived types")] - public sealed override Task Legacy_AnyTagEqualTo_array() => Task.CompletedTask; - - [Obsolete("Not used by derived types")] - public sealed override Task Legacy_AnyTagEqualTo_List() => Task.CompletedTask; - - public abstract class QueryFixture : BasicFilterTests.Fixture - { - private static readonly Random s_random = new(); - - public override string CollectionName => "QueryTests"; - - /// - /// Use random vectors to make sure that the values don't matter for GetAsync. - /// - protected override ReadOnlyMemory GetVector(int count) -#pragma warning disable CA5394 // Do not use insecure randomness - => new(Enumerable.Range(0, count).Select(_ => (float)s_random.NextDouble()).ToArray()); -#pragma warning restore CA5394 // Do not use insecure randomness - } -} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/Filter/BasicFilterTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/FilterTests.cs similarity index 92% rename from dotnet/test/VectorData/VectorData.ConformanceTests/Filter/BasicFilterTests.cs rename to dotnet/test/VectorData/VectorData.ConformanceTests/FilterTests.cs index 38cb61bb5af4..62de8da12ff3 100644 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/Filter/BasicFilterTests.cs +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/FilterTests.cs @@ -10,9 +10,9 @@ #pragma warning disable CS0252 // Possible unintended reference comparison; left hand side needs cast #pragma warning disable RCS1098 // Constant values should be placed on right side of comparisons -namespace VectorData.ConformanceTests.Filter; +namespace VectorData.ConformanceTests; -public abstract class BasicFilterTests(BasicFilterTests.Fixture fixture) +public abstract class FilterTests(FilterTests.Fixture fixture) where TKey : notnull { #region Equality @@ -46,8 +46,10 @@ public virtual async Task Equal_with_string_sql_injection_in_name() if (fixture.TestDynamic) { await Assert.ThrowsAsync( - () => this.GetDynamicRecords(r => r["String = \"not\"; DROP TABLE FilterTests;"] == "", - fixture.TestData.Count, new ReadOnlyMemory([1, 2, 3]))); + async () => await fixture.DynamicCollection.SearchAsync( + new ReadOnlyMemory([1, 2, 3]), + top: 1, + new() { Filter = r => r["String = \"not\"; DROP TABLE FilterTests;"] == "" }).ToListAsync()); } } @@ -472,22 +474,6 @@ public virtual Task Legacy_AnyTagEqualTo_List() #endregion Legacy filter support - protected virtual async Task> GetRecords( - Expression> filter, int top, ReadOnlyMemory vector) - => await fixture.Collection.SearchAsync( - vector, - top: top, - new() { Filter = filter }) - .Select(r => r.Record).OrderBy(r => r.Key).ToListAsync(); - - protected virtual async Task>> GetDynamicRecords( - Expression, bool>> dynamicFilter, int top, ReadOnlyMemory vector) - => await fixture.DynamicCollection.SearchAsync( - vector, - top: top, - new() { Filter = dynamicFilter }) - .Select(r => r.Record).OrderBy(r => r[nameof(FilterRecord.Key)]).ToListAsync(); - protected virtual async Task TestFilterAsync( Expression> filter, Expression, bool>> dynamicFilter, @@ -516,7 +502,13 @@ protected virtual async Task TestFilterAsync( // Execute the query against the vector store, once using the strongly typed filter // and once using the dynamic filter - var actual = await this.GetRecords(filter, fixture.TestData.Count, new ReadOnlyMemory([1, 2, 3])); + var actual = await fixture.Collection.SearchAsync( + new ReadOnlyMemory([1, 2, 3]), + top: fixture.TestData.Count, + new() { Filter = filter }) + .Select(r => r.Record) + .OrderBy(r => r.Key) + .ToListAsync(); if (actual.Count != expected.Count) { @@ -530,7 +522,13 @@ protected virtual async Task TestFilterAsync( if (fixture.TestDynamic) { - var dynamicActual = await this.GetDynamicRecords(dynamicFilter, fixture.TestData.Count, new ReadOnlyMemory([1, 2, 3])); + var dynamicActual = await fixture.DynamicCollection.SearchAsync( + new ReadOnlyMemory([1, 2, 3]), + top: fixture.TestData.Count, + new() { Filter = dynamicFilter }) + .Select(r => r.Record) + .OrderBy(r => r[nameof(FilterRecord.Key)]) + .ToListAsync(); if (dynamicActual.Count != expected.Count) { @@ -578,9 +576,8 @@ protected virtual async Task TestLegacyFilterAsync( } } - public class FilterRecord + public class FilterRecord : TestRecord { - public TKey Key { get; set; } = default!; public ReadOnlyMemory? Vector { get; set; } public int Int { get; set; } @@ -597,11 +594,6 @@ public abstract class Fixture : VectorStoreCollectionFixture public virtual string SpecialCharactersText => """>with $om[ specia]"chara GetVector(int count) - // All records have the same vector - this fixture is about testing criteria filtering only - // Derived types may override this to provide different vectors for different records. - => new(Enumerable.Range(1, count).Select(i => (float)i).ToArray()); - public virtual VectorStoreCollection> DynamicCollection { get; protected set; } = null!; public virtual bool TestDynamic => true; @@ -639,6 +631,9 @@ public override VectorStoreCollectionDefinition CreateRecordDefinition() protected override List BuildTestData() { + // All records have the same vector - this fixture is about testing criteria filtering only + var vector = new ReadOnlyMemory([1, 2, 3]); + return [ new() @@ -650,7 +645,7 @@ protected override List BuildTestData() Int2 = 80, StringArray = ["x", "y"], StringList = ["x", "y"], - Vector = this.GetVector(3) + Vector = vector }, new() { @@ -661,7 +656,7 @@ protected override List BuildTestData() Int2 = 90, StringArray = ["a", "b"], StringList = ["a", "b"], - Vector = this.GetVector(3) + Vector = vector }, new() { @@ -672,7 +667,7 @@ protected override List BuildTestData() Int2 = 9, StringArray = ["x"], StringList = ["x"], - Vector = this.GetVector(3) + Vector = vector }, new() { @@ -683,7 +678,7 @@ protected override List BuildTestData() Int2 = 100, StringArray = ["x", "y", "z"], StringList = ["x", "y", "z"], - Vector = this.GetVector(3) + Vector = vector }, new() { @@ -694,7 +689,7 @@ protected override List BuildTestData() Int2 = 101, StringArray = ["y", "z"], StringList = ["y", "z"], - Vector = this.GetVector(3) + Vector = vector } ]; } diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/HybridSearch/KeywordVectorizedHybridSearchComplianceTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/HybridSearch/KeywordVectorizedHybridSearchComplianceTests.cs index d27b3f4fe6aa..451ff2bcd00f 100644 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/HybridSearch/KeywordVectorizedHybridSearchComplianceTests.cs +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/HybridSearch/KeywordVectorizedHybridSearchComplianceTests.cs @@ -142,10 +142,8 @@ public async Task SearchWithMultiTextRecordSearchesRequestedFieldAsync() Assert.Equal(2, results2[1].Record.Code); } - public sealed class VectorAndStringRecord + public sealed class VectorAndStringRecord : TestRecord { - public TRecordKey Key { get; set; } = default!; - public string Text { get; set; } = string.Empty; public int Code { get; set; } @@ -153,10 +151,8 @@ public sealed class VectorAndStringRecord public ReadOnlyMemory Vector { get; set; } } - public sealed class MultiTextStringRecord + public sealed class MultiTextStringRecord : TestRecord { - public TRecordKey Key { get; set; } = default!; - public string Text1 { get; set; } = string.Empty; public string Text2 { get; set; } = string.Empty; diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/ModelTests/BasicModelTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/ModelTests/BasicModelTests.cs new file mode 100644 index 000000000000..22a70438d16c --- /dev/null +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/ModelTests/BasicModelTests.cs @@ -0,0 +1,485 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Microsoft.Extensions.VectorData; +using VectorData.ConformanceTests.Support; +using VectorData.ConformanceTests.Xunit; +using Xunit; + +namespace VectorData.ConformanceTests.ModelTests; + +public abstract class BasicModelTests(BasicModelTests.Fixture fixture) : IAsyncLifetime + where TKey : notnull +{ + #region Get + + [ConditionalTheory, MemberData(nameof(IncludeVectorsData))] + public virtual async Task GetAsync_single_record(bool includeVectors) + { + var expectedRecord = fixture.TestData[0]; + + var received = await this.Collection.GetAsync(expectedRecord.Key, new() { IncludeVectors = includeVectors }); + + expectedRecord.AssertEqual(received, includeVectors, fixture.TestStore.VectorsComparable); + } + + [ConditionalTheory, MemberData(nameof(IncludeVectorsData))] + public virtual async Task GetAsync_multiple_records(bool includeVectors) + { + var expectedRecords = fixture.TestData.Take(2); + var ids = expectedRecords.Select(record => record.Key); + + var received = await this.Collection.GetAsync(ids, new() { IncludeVectors = includeVectors }).ToArrayAsync(); + + foreach (var record in expectedRecords) + { + record.AssertEqual( + received.Single(r => r.Key.Equals(record.Key)), + includeVectors, + fixture.TestStore.VectorsComparable); + } + } + + [ConditionalFact] + public virtual async Task GetAsync_throws_for_null_key() + { + // Skip this test for value type keys + if (default(TKey) is not null) + { + return; + } + + ArgumentNullException ex = await Assert.ThrowsAsync(() => this.Collection.GetAsync((TKey)default!)); + Assert.Equal("key", ex.ParamName); + } + + [ConditionalFact] + public virtual async Task GetAsync_throws_for_null_keys() + { + ArgumentNullException ex = await Assert.ThrowsAsync(() => this.Collection.GetAsync(keys: null!).ToArrayAsync().AsTask()); + Assert.Equal("keys", ex.ParamName); + } + + [ConditionalFact] + public virtual async Task GetAsync_returns_null_for_missing_key() + { + TKey key = fixture.GenerateNextKey(); + + Assert.Null(await this.Collection.GetAsync(key)); + } + + [ConditionalFact] + public virtual async Task GetAsync_returns_empty_for_empty_keys() + { + Assert.Empty(await this.Collection.GetAsync([]).ToArrayAsync()); + } + + [ConditionalTheory, MemberData(nameof(IncludeVectorsData))] + public virtual async Task GetAsync_with_filter(bool includeVectors) + { + var expectedRecord = fixture.TestData[0]; + + var results = await this.Collection.GetAsync( + r => r.Number == 1, + top: 2, + new() { IncludeVectors = includeVectors }) + .ToListAsync(); + + var receivedRecord = Assert.Single(results); + expectedRecord.AssertEqual(receivedRecord, includeVectors, fixture.TestStore.VectorsComparable); + } + + [ConditionalFact] + public virtual async Task GetAsync_with_filter_by_true() + { + Assert.True(fixture.TestData.Count < 100); + + var count = await this.Collection.GetAsync(r => true, top: 100).CountAsync(); + + Assert.Equal(fixture.TestData.Count, count); + } + + [ConditionalFact] + public virtual async Task GetAsync_with_filter_and_OrderBy() + { + var ascendingNumbers = fixture.TestData.Where(r => r.Number > 1).OrderBy(r => r.Number).Take(2).Select(r => r.Number).ToList(); + var descendingNumbers = fixture.TestData.Where(r => r.Number > 1).OrderByDescending(r => r.Number).Take(2).Select(r => r.Number).ToList(); + + // Make sure the actual results are different for ascending/descending, otherwise the test is meaningless + Assert.NotEqual(ascendingNumbers, descendingNumbers); + + var results = await this.Collection.GetAsync( + r => r.Number > 1, + top: 2, + new() { OrderBy = o => o.Ascending(r => r.Number) }) + .Select(r => r.Number) + .ToListAsync(); + + Assert.Equal(ascendingNumbers, results); + + results = await this.Collection.GetAsync( + r => r.Number > 1, + top: 2, + new() { OrderBy = o => o.Descending(r => r.Number) }) + .Select(r => r.Number) + .ToListAsync(); + + Assert.Equal(descendingNumbers, results); + } + + [ConditionalFact] + public virtual async Task GetAsync_with_filter_and_multiple_OrderBys() + { + var ascendingNumbers = fixture.TestData + .OrderByDescending(r => r.Text) + .ThenBy(r => r.Number) + .Take(2).Select(r => r.Number).ToList(); + var descendingNumbers = fixture.TestData + .OrderByDescending(r => r.Text) + .ThenByDescending(r => r.Number) + .Take(2) + .Select(r => r.Number) + .ToList(); + + // Make sure the actual results are different for ascending/descending, otherwise the test is meaningless + Assert.NotEqual(ascendingNumbers, descendingNumbers); + + var results = await this.Collection.GetAsync( + r => true, + top: 2, + new() { OrderBy = o => o.Descending(r => r.Text).Ascending(r => r.Number) }) + .Select(r => r.Number) + .ToListAsync(); + + Assert.Equal(ascendingNumbers, results); + + results = await this.Collection.GetAsync( + r => true, + top: 2, + new() { OrderBy = o => o.Descending(r => r.Text).Descending(r => r.Number) }) + .Select(r => r.Number) + .ToListAsync(); + + Assert.Equal(descendingNumbers, results); + } + + [ConditionalFact] + public virtual async Task GetAsync_with_filter_and_OrderBy_and_Skip() + { + var results = await this.Collection.GetAsync( + r => r.Number > 1, + top: 2, + new() { OrderBy = o => o.Ascending(r => r.Number), Skip = 1 }) + .Select(r => r.Number) + .ToListAsync(); + + Assert.Equal( + fixture.TestData.Where(r => r.Number > 1).OrderBy(r => r.Number).Skip(1).Take(2).Select(r => r.Number), + results); + } + + #endregion Get + + #region Upsert + + [ConditionalFact] + public virtual async Task Insert_single_record() + { + TKey expectedKey = fixture.GenerateNextKey(); + Record inserted = new() + { + Key = expectedKey, + Text = "New record", + Number = 123, + Floats = new([10, 0, 0]) + }; + + Assert.Null(await this.Collection.GetAsync(expectedKey)); + await this.Collection.UpsertAsync(inserted); + + var received = await this.Collection.GetAsync(expectedKey, new() { IncludeVectors = true }); + inserted.AssertEqual(received, includeVectors: true, fixture.TestStore.VectorsComparable); + + await fixture.TestStore.WaitForDataAsync(this.Collection, recordCount: fixture.TestData.Count + 1); + } + + [ConditionalFact] + public virtual async Task Update_single_record() + { + var existingRecord = fixture.TestData[1]; + Record updated = new() + { + Key = existingRecord.Key, + Text = "Updated record", + Number = 456, + Floats = new([10, 0, 0]) + }; + + Assert.NotNull(await this.Collection.GetAsync(existingRecord.Key)); + await this.Collection.UpsertAsync(updated); + + var received = await this.Collection.GetAsync(existingRecord.Key, new() { IncludeVectors = true }); + updated.AssertEqual(received, includeVectors: true, fixture.TestStore.VectorsComparable); + } + + [ConditionalFact] + public virtual async Task Insert_multiple_records() + { + Record[] newRecords = + [ + new() + { + Key = fixture.GenerateNextKey(), + Number = 100, + Text = "New record 1", + Floats = new([10, 0, 1]) + }, + new() + { + Key = fixture.GenerateNextKey(), + Number = 101, + Text = "New record 2", + Floats = new([10, 0, 2]) + }, + ]; + + var keys = newRecords.Select(record => record.Key).ToArray(); + Assert.Empty(await this.Collection.GetAsync(keys).ToArrayAsync()); + + await this.Collection.UpsertAsync(newRecords); + + var received = await this.Collection.GetAsync(keys, new() { IncludeVectors = true }).ToArrayAsync(); + + Assert.Collection( + received.OrderBy(r => r.Number), + r => newRecords[0].AssertEqual(r, includeVectors: true, fixture.TestStore.VectorsComparable), + r => newRecords[1].AssertEqual(r, includeVectors: true, fixture.TestStore.VectorsComparable)); + } + + [ConditionalFact] + public virtual async Task Update_multiple_records() + { + Record[] existingRecords = + [ + new() + { + Key = fixture.TestData[0].Key, + Number = 101, + Text = "Updated record 1", + Floats = new([10, 0, 1]) + }, + new() + { + Key = fixture.TestData[1].Key, + Number = 102, + Text = "Updated record 2", + Floats = new([10, 0, 2]) + } + ]; + + await this.Collection.UpsertAsync(existingRecords); + + var keys = existingRecords.Select(record => record.Key).ToArray(); + var received = await this.Collection.GetAsync(keys, new() { IncludeVectors = true }).ToArrayAsync(); + + Assert.Collection( + received.OrderBy(r => r.Number), + r => existingRecords[0].AssertEqual(r, includeVectors: true, fixture.TestStore.VectorsComparable), + r => existingRecords[1].AssertEqual(r, includeVectors: true, fixture.TestStore.VectorsComparable)); + } + + [ConditionalFact] + public virtual async Task Insert_and_update_in_same_batch() + { + Record[] records = + [ + new() + { + Key = fixture.GenerateNextKey(), + Number = 101, + Text = "New record", + Floats = new([10, 0, 1]) + }, + new() + { + Key = fixture.TestData[0].Key, + Number = 102, + Text = "Updated record", + Floats = new([10, 0, 2]) + }, + ]; + + await this.Collection.UpsertAsync(records); + + var keys = records.Select(record => record.Key).ToArray(); + var received = await this.Collection.GetAsync(keys, new() { IncludeVectors = true }).ToArrayAsync(); + + Assert.Collection( + received.OrderBy(r => r.Number), + r => records[0].AssertEqual(r, includeVectors: true, fixture.TestStore.VectorsComparable), + r => records[1].AssertEqual(r, includeVectors: true, fixture.TestStore.VectorsComparable)); + } + + [ConditionalFact] + public virtual async Task UpsertAsync_throws_for_null_batch() + { + ArgumentNullException ex = await Assert.ThrowsAsync(() => this.Collection.UpsertAsync(records: null!)); + Assert.Equal("records", ex.ParamName); + } + + [ConditionalFact] + public virtual async Task UpsertAsync_does_nothing_for_empty_batch() + { + Assert.True(fixture.TestData.Count < 100); + + var beforeCount = await this.Collection.GetAsync(r => true, top: 100).CountAsync(); + await this.Collection.UpsertAsync([]); + var afterCount = await this.Collection.GetAsync(r => true, top: 100).CountAsync(); + + Assert.Equal(afterCount, beforeCount); + } + + #endregion Upsert + + #region Delete + + [ConditionalFact] + public virtual async Task Delete_single_record() + { + var keyToRemove = fixture.TestData[0].Key; + + await this.Collection.DeleteAsync(keyToRemove); + Assert.Null(await this.Collection.GetAsync(keyToRemove)); + } + + [ConditionalFact] + public virtual async Task Delete_multiple_records() + { + TKey[] keysToRemove = [fixture.TestData[0].Key, fixture.TestData[1].Key]; + + await this.Collection.DeleteAsync(keysToRemove); + Assert.Empty(await this.Collection.GetAsync(keysToRemove).ToArrayAsync()); + } + + [ConditionalFact] + public virtual async Task DeleteAsync_does_nothing_for_non_existing_key() + { + var beforeCount = await this.Collection.GetAsync(r => true, top: 100).CountAsync(); + await this.Collection.DeleteAsync(fixture.GenerateNextKey()); + var afterCount = await this.Collection.GetAsync(r => true, top: 100).CountAsync(); + + Assert.Equal(afterCount, beforeCount); + } + + [ConditionalFact] + public virtual async Task DeleteAsync_does_nothing_for_empty_batch() + { + var beforeCount = await this.Collection.GetAsync(r => true, top: 100).CountAsync(); + await this.Collection.DeleteAsync([]); + var afterCount = await this.Collection.GetAsync(r => true, top: 100).CountAsync(); + + Assert.Equal(afterCount, beforeCount); + } + + [ConditionalFact] + public virtual async Task DeleteAsync_throws_for_null_keys() + { + ArgumentNullException ex = await Assert.ThrowsAsync(() => this.Collection.DeleteAsync(keys: null!)); + Assert.Equal("keys", ex.ParamName); + } + + #endregion Delete + + protected VectorStoreCollection Collection => fixture.Collection; + + public abstract class Fixture : VectorStoreCollectionFixture + { + public override string CollectionName => "BasicModelTests"; + + protected override List BuildTestData() => + [ + new() + { + Key = this.GenerateNextKey(), + Number = 1, + Text = "foo", + Floats = new([1, 2, 3]) + }, + new() + { + Key = this.GenerateNextKey(), + Number = 2, + Text = "bar", + Floats = new([1, 2, 4]) + }, + new() + { + Key = this.GenerateNextKey(), + Number = 3, + Text = "foo", // identical text as above + Floats = new([1, 2, 5]) + } + ]; + + public override VectorStoreCollectionDefinition CreateRecordDefinition() + => new() + { + Properties = + [ + new VectorStoreKeyProperty(nameof(Record.Key), typeof(TKey)), + new VectorStoreVectorProperty(nameof(Record.Floats), typeof(ReadOnlyMemory), 3) + { + DistanceFunction = this.DistanceFunction, + IndexKind = this.IndexKind + }, + + new VectorStoreDataProperty(nameof(Record.Number), typeof(int)) { IsIndexed = true }, + new VectorStoreDataProperty(nameof(Record.Text), typeof(string)) { IsIndexed = true }, + ] + }; + } + + public sealed class Record : TestRecord + { + [VectorStoreData(StorageName = "text")] + public string? Text { get; set; } + + [VectorStoreData(StorageName = "number")] + public int Number { get; set; } + + [VectorStoreVector(Dimensions: 3, StorageName = "embedding")] + public ReadOnlyMemory Floats { get; set; } + + public void AssertEqual(Record? other, bool includeVectors, bool compareVectors) + { + Assert.NotNull(other); + Assert.Equal(this.Key, other.Key); + Assert.Equal(this.Text, other.Text); + Assert.Equal(this.Number, other.Number); + + if (includeVectors) + { + Assert.Equal(this.Floats.Span.Length, other.Floats.Span.Length); + + if (compareVectors) + { + Assert.Equal(this.Floats.ToArray(), other.Floats.ToArray()); + } + } + else + { + Assert.Equal(0, other.Floats.Length); + } + } + + public override string ToString() + => $"Key: {this.Key}, Text: {this.Text}"; + } + + public Task InitializeAsync() + => fixture.ReseedAsync(); + + public Task DisposeAsync() + => Task.CompletedTask; + + public static readonly TheoryData IncludeVectorsData = [false, true]; +} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/ModelTests/DynamicModelTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/ModelTests/DynamicModelTests.cs new file mode 100644 index 000000000000..e27fac2eefe8 --- /dev/null +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/ModelTests/DynamicModelTests.cs @@ -0,0 +1,408 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Microsoft.Extensions.VectorData; +using VectorData.ConformanceTests.Support; +using VectorData.ConformanceTests.Xunit; +using Xunit; + +namespace VectorData.ConformanceTests.ModelTests; + +public abstract class DynamicModelTests(DynamicModelTests.Fixture fixture) : IAsyncLifetime + where TKey : notnull +{ + #region Get + + [ConditionalTheory, MemberData(nameof(IncludeVectorsData))] + public virtual async Task GetAsync_single_record(bool includeVectors) + { + var expectedRecord = fixture.TestData[0]; + + var received = await fixture.Collection.GetAsync( + (TKey)expectedRecord[DynamicDataModelFixture.KeyPropertyName]!, + new() { IncludeVectors = includeVectors }); + + AssertEquivalent(expectedRecord, received, includeVectors, fixture.TestStore.VectorsComparable); + } + + // TODO: https://github.com/microsoft/semantic-kernel/issues/13303 + // [ConditionalTheory, MemberData(nameof(IncludeVectorsData))] + // public virtual Task GetAsync_multiple_records(bool includeVectors) + // { + // var expectedRecords = fixture.TestData.Take(2); + // var ids = expectedRecords.Select(record => record[KeyPropertyName]!); + + // var received = await fixture.Collection.GetAsync(ids, new() { IncludeVectors = includeVectors }).ToArrayAsync(); + + // foreach (var record in expectedRecords) + // { + // AssertEquivalent( + // record, + // received.Single(r => r[KeyPropertyName]!.Equals(record[KeyPropertyName])), + // includeVectors, + // fixture.TestStore.VectorsComparable); + // } + // } + + [ConditionalFact] + public virtual async Task GetAsync_throws_for_null_key() + { + // Skip this test for value type keys + if (default(TKey) is not null) + { + return; + } + + ArgumentNullException ex = await Assert.ThrowsAsync(() => fixture.Collection.GetAsync((TKey)default!)); + Assert.Equal("key", ex.ParamName); + } + + [ConditionalFact] + public virtual async Task GetAsync_throws_for_null_keys() + { + ArgumentNullException ex = await Assert.ThrowsAsync(() => fixture.Collection.GetAsync(keys: null!).ToArrayAsync().AsTask()); + Assert.Equal("keys", ex.ParamName); + } + + [ConditionalFact] + public virtual async Task GetAsync_returns_null_for_missing_key() + { + TKey key = fixture.GenerateNextKey(); + + Assert.Null(await fixture.Collection.GetAsync(key)); + } + + [ConditionalFact] + public virtual async Task GetAsync_returns_empty_for_empty_keys() + { + Assert.Empty(await fixture.Collection.GetAsync([]).ToArrayAsync()); + } + + [ConditionalTheory, MemberData(nameof(IncludeVectorsData))] + public virtual async Task GetAsync_with_filter(bool includeVectors) + { + var expectedRecord = fixture.TestData[0]; + + var results = await fixture.Collection.GetAsync( + r => (int)r[IntegerPropertyName]! == 1, + top: 2, + new() { IncludeVectors = includeVectors }) + .ToListAsync(); + + var receivedRecord = Assert.Single(results); + AssertEquivalent(expectedRecord, receivedRecord, includeVectors, fixture.TestStore.VectorsComparable); + } + + [ConditionalFact] + public virtual async Task GetAsync_with_filter_by_true() + { + var count = await fixture.Collection.GetAsync(r => true, top: 100).CountAsync(); + Assert.Equal(fixture.TestData.Count, count); + Assert.True(count < 100); + } + + [ConditionalFact] + public virtual async Task GetAsync_with_filter_and_OrderBy() + { + var ascendingNumbers = fixture.TestData + .Where(r => (int)r[IntegerPropertyName]! > 1) + .OrderBy(r => r[IntegerPropertyName]) + .Take(2) + .Select(r => (int)r[IntegerPropertyName]!) + .ToList(); + + var descendingNumbers = fixture.TestData + .Where(r => (int)r[IntegerPropertyName]! > 1) + .OrderByDescending(r => r[IntegerPropertyName]) + .Take(2) + .Select(r => (int)r[IntegerPropertyName]!) + .ToList(); + + // Make sure the actual results are different for ascending/descending, otherwise the test is meaningless + Assert.NotEqual(ascendingNumbers, descendingNumbers); + + // Finally, query once with ascending and once with descending, comparing against the expected results above. + var results = await fixture.Collection.GetAsync( + r => (int)r[IntegerPropertyName]! > 1, + top: 2, + new() { OrderBy = o => o.Ascending(r => r[IntegerPropertyName]) }) + .Select(r => (int)r[IntegerPropertyName]!) + .ToListAsync(); + + Assert.Equal(ascendingNumbers, results); + + results = await fixture.Collection.GetAsync( + r => (int)r[IntegerPropertyName]! > 1, + top: 2, + new() { OrderBy = o => o.Descending(r => r[IntegerPropertyName]) }) + .Select(r => (int)r[IntegerPropertyName]!) + .ToListAsync(); + + Assert.Equal(descendingNumbers, results); + } + + [ConditionalFact] + public virtual async Task GetAsync_with_filter_and_multiple_OrderBys() + { + var ascendingNumbers = fixture.TestData + .OrderByDescending(r => r[StringPropertyName]) + .ThenBy(r => r[IntegerPropertyName]) + .Take(2) + .Select(r => (int)r[IntegerPropertyName]!) + .ToList(); + + var descendingNumbers = fixture.TestData + .OrderByDescending(r => r[StringPropertyName]) + .ThenByDescending(r => r[IntegerPropertyName]) + .Take(2) + .Select(r => (int)r[IntegerPropertyName]!) + .ToList(); + + // Make sure the actual results are different for ascending/descending, otherwise the test is meaningless + Assert.NotEqual(ascendingNumbers, descendingNumbers); + + var results = await fixture.Collection.GetAsync( + r => true, + top: 2, + new() { OrderBy = o => o.Descending(r => r[StringPropertyName]).Ascending(r => r[IntegerPropertyName]) }) + .Select(r => (int)r[IntegerPropertyName]!) + .ToListAsync(); + + Assert.Equal(ascendingNumbers, results); + + results = await fixture.Collection.GetAsync( + r => true, + top: 2, + new() { OrderBy = o => o.Descending(r => r[StringPropertyName]).Descending(r => r[IntegerPropertyName]) }) + .Select(r => (int)r[IntegerPropertyName]!) + .ToListAsync(); + + Assert.Equal(descendingNumbers, results); + } + + [ConditionalFact] + public virtual async Task GetAsync_with_filter_and_OrderBy_and_Skip() + { + var results = await fixture.Collection.GetAsync( + r => (int)r[IntegerPropertyName]! > 1, + top: 2, + new() { OrderBy = o => o.Ascending(r => r[IntegerPropertyName]), Skip = 1 }) + .Select(r => (int)r[IntegerPropertyName]!) + .ToListAsync(); + + Assert.Equal( + fixture.TestData + .Where(r => (int)r[IntegerPropertyName]! > 1) + .OrderBy(r => r[IntegerPropertyName]) + .Skip(1) + .Take(2) + .Select(r => (int)r[IntegerPropertyName]!), + results); + } + + #endregion Get + + #region Upsert + + [ConditionalFact] + public virtual async Task Insert_single_record() + { + TKey expectedKey = fixture.GenerateNextKey(); + var inserted = new Dictionary + { + [DynamicDataModelFixture.KeyPropertyName] = expectedKey, + [DynamicDataModelFixture.StringPropertyName] = "some", + [DynamicDataModelFixture.IntegerPropertyName] = 123, + [DynamicDataModelFixture.EmbeddingPropertyName] = new ReadOnlyMemory(Enumerable.Repeat(0.1f, DynamicDataModelFixture.DimensionCount).ToArray()) + }; + + Assert.Null(await this.Collection.GetAsync(expectedKey)); + await this.Collection.UpsertAsync(inserted); + + var received = await this.Collection.GetAsync(expectedKey, new() { IncludeVectors = true }); + AssertEquivalent(inserted, received, includeVectors: true, fixture.TestStore.VectorsComparable); + } + + [ConditionalFact] + public virtual async Task Update_single_record() + { + var existingRecord = fixture.TestData[1]; + var updated = new Dictionary + { + [KeyPropertyName] = existingRecord[KeyPropertyName], + [StringPropertyName] = "different", + [IntegerPropertyName] = 456, + [EmbeddingPropertyName] = new ReadOnlyMemory(Enumerable.Repeat(0.7f, 3).ToArray()) + }; + + Assert.NotNull(await this.Collection.GetAsync((TKey)existingRecord[KeyPropertyName]!)); + await this.Collection.UpsertAsync(updated); + + var received = await this.Collection.GetAsync((TKey)existingRecord[KeyPropertyName]!, new() { IncludeVectors = true }); + AssertEquivalent(updated, received, includeVectors: true, fixture.TestStore.VectorsComparable); + } + + // TODO: https://github.com/microsoft/semantic-kernel/issues/13303 + // [ConditionalFact] + // public virtual async Task Insert_multiple_records() + // { + // Dictionary[] newRecords = + // [ + // new() + // { + // [KeyPropertyName] = fixture.GenerateNextKey(), + // [IntegerPropertyName] = 100, + // [StringPropertyName] = "New record 1", + // [EmbeddingPropertyName] = new ReadOnlyMemory([10, 0, 1]) + // }, + // new() + // { + // [KeyPropertyName] = fixture.GenerateNextKey(), + // [IntegerPropertyName] = 101, + // [StringPropertyName] = "New record 2", + // [EmbeddingPropertyName] = new ReadOnlyMemory([10, 0, 2]) + // }, + // ]; + + // var keys = newRecords.Select(record => record[KeyPropertyName]!).ToArray(); + // Assert.Empty(await this.Collection.GetAsync(keys).ToArrayAsync()); + + // await this.Collection.UpsertAsync(newRecords); + + // var received = await this.Collection.GetAsync(keys, new() { IncludeVectors = true }).ToArrayAsync(); + + // Assert.Collection( + // received.OrderBy(r => r[IntegerPropertyName]), + // r => AssertEquivalent(newRecords[0], r, includeVectors: true, fixture.TestStore.VectorsComparable), + // r => AssertEquivalent(newRecords[1], r, includeVectors: true, fixture.TestStore.VectorsComparable)); + + // Assert.Equal(fixture.TestData.Count + 2, await this.GetRecordCount()); + // } + + #endregion Upsert + + #region Delete + + [ConditionalFact] + public async Task Delete_single_record() + { + var recordToRemove = fixture.TestData[2]; + + Assert.NotNull(await fixture.Collection.GetAsync((TKey)recordToRemove[DynamicDataModelFixture.KeyPropertyName]!)); + await fixture.Collection.DeleteAsync((TKey)recordToRemove[DynamicDataModelFixture.KeyPropertyName]!); + Assert.Null(await fixture.Collection.GetAsync((TKey)recordToRemove[DynamicDataModelFixture.KeyPropertyName]!)); + } + + // TODO: https://github.com/microsoft/semantic-kernel/issues/13303 + // [ConditionalFact] + // public virtual async Task Delete_multiple_records() + // { + // TKey[] keysToRemove = [(TKey)fixture.TestData[0][KeyPropertyName]!, (TKey)fixture.TestData[1][KeyPropertyName]!]; + + // await this.Collection.DeleteAsync(keysToRemove); + // Assert.Empty(await this.Collection.GetAsync(keysToRemove).ToArrayAsync()); + + // Assert.Equal(fixture.TestData.Count - 2, await this.GetRecordCount()); + // } + + [ConditionalFact] + public virtual async Task DeleteAsync_does_nothing_for_non_existing_key() + { + TKey key = fixture.GenerateNextKey(); + + await fixture.Collection.DeleteAsync(key); + } + + #endregion Delete + + protected static void AssertEquivalent(Dictionary expected, Dictionary? actual, bool includeVectors, bool compareVectors) + { + Assert.NotNull(actual); + Assert.Equal(expected[KeyPropertyName], actual[KeyPropertyName]); + + Assert.Equal(expected[StringPropertyName], actual[StringPropertyName]); + Assert.Equal(expected[IntegerPropertyName], actual[IntegerPropertyName]); + + if (includeVectors) + { + Assert.Equal( + ((ReadOnlyMemory)expected[EmbeddingPropertyName]!).Length, + ((ReadOnlyMemory)actual[EmbeddingPropertyName]!).Length); + + if (compareVectors) + { + Assert.Equal( + ((ReadOnlyMemory)expected[EmbeddingPropertyName]!).ToArray(), + ((ReadOnlyMemory)actual[EmbeddingPropertyName]!).ToArray()); + } + } + else + { + Assert.False(actual.ContainsKey(EmbeddingPropertyName)); + } + } + + public const string KeyPropertyName = "key"; + public const string StringPropertyName = "text"; + public const string IntegerPropertyName = "integer"; + public const string EmbeddingPropertyName = "embedding"; + + protected VectorStoreCollection> Collection => fixture.Collection; + + public abstract class Fixture : DynamicVectorStoreCollectionFixture + { + public override string CollectionName => "DynamicModelTests"; + protected override string KeyPropertyName => DynamicModelTests.KeyPropertyName; + + protected override VectorStoreCollection> GetCollection() + => this.TestStore.DefaultVectorStore.GetDynamicCollection(this.CollectionName, this.CreateRecordDefinition()); + + public override VectorStoreCollectionDefinition CreateRecordDefinition() + => new() + { + Properties = + [ + new VectorStoreKeyProperty(this.KeyPropertyName, typeof(TKey)), + new VectorStoreDataProperty(StringPropertyName, typeof(string)) { IsIndexed = true}, + new VectorStoreDataProperty(IntegerPropertyName, typeof(int)) { IsIndexed = true }, + new VectorStoreVectorProperty(EmbeddingPropertyName, typeof(ReadOnlyMemory), dimensions: 3) + { + DistanceFunction = this.DistanceFunction, + IndexKind = this.IndexKind + } + ] + }; + + protected override List> BuildTestData() => + [ + new() + { + [this.KeyPropertyName] = this.GenerateNextKey(), + [StringPropertyName] = "foo", + [IntegerPropertyName] = 1, + [EmbeddingPropertyName] = new ReadOnlyMemory([1, 2, 3]) + }, + new() + { + [this.KeyPropertyName] = this.GenerateNextKey(), + [StringPropertyName] = "bar", + [IntegerPropertyName] = 2, + [EmbeddingPropertyName] = new ReadOnlyMemory([1, 2, 4]) + }, + new() + { + [this.KeyPropertyName] = this.GenerateNextKey(), + [StringPropertyName] = "foo", // identical text as above + [IntegerPropertyName] = 3, + [EmbeddingPropertyName] = new ReadOnlyMemory([1, 2, 5]) + } + ]; + } + + public Task InitializeAsync() + => fixture.ReseedAsync(); + + public Task DisposeAsync() + => Task.CompletedTask; + + public static readonly TheoryData IncludeVectorsData = [false, true]; +} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/ModelTests/NoDataModelTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/ModelTests/NoDataModelTests.cs new file mode 100644 index 000000000000..2cd30efb41dd --- /dev/null +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/ModelTests/NoDataModelTests.cs @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Microsoft.Extensions.VectorData; +using VectorData.ConformanceTests.Support; +using VectorData.ConformanceTests.Xunit; +using Xunit; + +namespace VectorData.ConformanceTests.ModelTests; + +/// +/// Tests using a model without data fields, only a key and an embedding. +/// +public class NoDataModelTests(NoDataModelTests.Fixture fixture) : IAsyncLifetime + where TKey : notnull +{ + [ConditionalTheory, MemberData(nameof(IncludeVectorsData))] + public virtual async Task GetAsync_single_record(bool includeVectors) + { + var expectedRecord = fixture.TestData[0]; + + var received = await this.Collection.GetAsync(expectedRecord.Key, new() { IncludeVectors = includeVectors }); + + expectedRecord.AssertEqual(received, includeVectors, fixture.TestStore.VectorsComparable); + } + + [ConditionalFact] + public virtual async Task Insert_single_record() + { + TKey expectedKey = fixture.GenerateNextKey(); + NoDataRecord inserted = new() + { + Key = expectedKey, + Floats = new([10, 0, 0]) + }; + + Assert.Null(await this.Collection.GetAsync(expectedKey)); + await this.Collection.UpsertAsync(inserted); + + var received = await this.Collection.GetAsync(expectedKey, new() { IncludeVectors = true }); + inserted.AssertEqual(received, includeVectors: true, fixture.TestStore.VectorsComparable); + } + + [ConditionalFact] + public virtual async Task Delete_single_record() + { + var keyToRemove = fixture.TestData[0].Key; + + await this.Collection.DeleteAsync(keyToRemove); + Assert.Null(await this.Collection.GetAsync(keyToRemove)); + } + + protected VectorStoreCollection Collection => fixture.Collection; + + public abstract class Fixture : VectorStoreCollectionFixture + { + public override string CollectionName => "NoDataModelTests"; + + protected override List BuildTestData() => + [ + new() + { + Key = this.GenerateNextKey(), + Floats = new([1, 2, 3]) + }, + new() + { + Key = this.GenerateNextKey(), + Floats = new([1, 2, 4]) + } + ]; + + public override VectorStoreCollectionDefinition CreateRecordDefinition() + => new() + { + Properties = + [ + new VectorStoreKeyProperty(nameof(NoDataRecord.Key), typeof(TKey)), + new VectorStoreVectorProperty(nameof(NoDataRecord.Floats), typeof(ReadOnlyMemory), 3) + { + IndexKind = this.IndexKind + } + ] + }; + } + + public sealed class NoDataRecord : TestRecord + { + [VectorStoreVector(Dimensions: 3, StorageName = "embedding")] + public ReadOnlyMemory Floats { get; set; } + + public void AssertEqual(NoDataRecord? other, bool includeVectors, bool compareVectors) + { + Assert.NotNull(other); + Assert.Equal(this.Key, other.Key); + + if (includeVectors) + { + Assert.Equal(this.Floats.Span.Length, other.Floats.Span.Length); + + if (compareVectors) + { + Assert.True(this.Floats.Span.SequenceEqual(other.Floats.Span)); + } + } + } + } + + public Task InitializeAsync() + => fixture.ReseedAsync(); + + public Task DisposeAsync() + => Task.CompletedTask; + + public static readonly TheoryData IncludeVectorsData = [false, true]; +} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/ModelTests/NoVectorConformanceTests.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/ModelTests/NoVectorConformanceTests.cs new file mode 100644 index 000000000000..e6bdb6a8e652 --- /dev/null +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/ModelTests/NoVectorConformanceTests.cs @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Microsoft.Extensions.VectorData; +using VectorData.ConformanceTests.Support; +using VectorData.ConformanceTests.Xunit; +using Xunit; + +namespace VectorData.ConformanceTests.ModelTests; + +/// +/// Tests operations using a model without a vector. +/// This is only supported by a subset of databases so only extend if applicable for your database. +/// +public class NoVectorModelTests(NoVectorModelTests.Fixture fixture) : IAsyncLifetime + where TKey : notnull +{ + [ConditionalTheory, MemberData(nameof(IncludeVectorsData))] + public virtual async Task GetAsync_single_record(bool includeVectors) + { + var expectedRecord = fixture.TestData[0]; + + var received = await this.Collection.GetAsync(expectedRecord.Key, new() { IncludeVectors = includeVectors }); + + expectedRecord.AssertEqual(received); + } + + [ConditionalFact] + public virtual async Task Insert_single_record() + { + TKey expectedKey = fixture.GenerateNextKey(); + NoVectorRecord inserted = new() + { + Key = expectedKey, + Text = "New record" + }; + + Assert.Null(await this.Collection.GetAsync(expectedKey)); + await this.Collection.UpsertAsync(inserted); + + var received = await this.Collection.GetAsync(expectedKey, new() { IncludeVectors = true }); + inserted.AssertEqual(received); + } + + [ConditionalFact] + public virtual async Task Delete_single_record() + { + var keyToRemove = fixture.TestData[0].Key; + + await this.Collection.DeleteAsync(keyToRemove); + Assert.Null(await this.Collection.GetAsync(keyToRemove)); + } + + protected VectorStoreCollection Collection => fixture.Collection; + + public abstract class Fixture : VectorStoreCollectionFixture + { + public override string CollectionName => "NoVectorModelTests"; + + protected override List BuildTestData() => + [ + new() + { + Key = this.GenerateNextKey(), + Text = "foo", + }, + new() + { + Key = this.GenerateNextKey(), + Text = "bar", + } + ]; + + public override VectorStoreCollectionDefinition CreateRecordDefinition() + => new() + { + Properties = + [ + new VectorStoreKeyProperty(nameof(NoVectorRecord.Key), typeof(TKey)), + new VectorStoreDataProperty(nameof(NoVectorRecord.Text), typeof(string)) { IsIndexed = true } + ] + }; + + // The default implementation of WaitForDataAsync uses SearchAsync, but our model has no vectors. + protected override async Task WaitForDataAsync() + { + for (var i = 0; i < 200; i++) + { + var results = await this.Collection.GetAsync([this.TestData[0].Key, this.TestData[1].Key]).ToArrayAsync(); + if (results.Length == this.TestData.Count && results.All(r => r != null)) + { + return; + } + + await Task.Delay(TimeSpan.FromMilliseconds(100)); + } + + throw new InvalidOperationException("Data did not appear in the collection within the expected time."); + } + } + + public sealed class NoVectorRecord : TestRecord + { + [VectorStoreData(StorageName = "text")] + public string? Text { get; set; } + + public void AssertEqual(NoVectorRecord? other) + { + Assert.NotNull(other); + Assert.Equal(this.Key, other.Key); + Assert.Equal(this.Text, other.Text); + } + } + + public Task InitializeAsync() + => fixture.ReseedAsync(); + + public Task DisposeAsync() + => Task.CompletedTask; + + public static readonly TheoryData IncludeVectorsData = [false, true]; +} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/Models/SimpleRecord.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/Models/SimpleRecord.cs index 49ae88f44a8b..8bc629e512d2 100644 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/Models/SimpleRecord.cs +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/Models/SimpleRecord.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using Microsoft.Extensions.VectorData; +using VectorData.ConformanceTests.Support; using Xunit; namespace VectorData.ConformanceTests.Models; @@ -10,13 +11,10 @@ namespace VectorData.ConformanceTests.Models; /// a key, int, string and an embedding. /// /// TKey is a generic parameter because different connectors support different key types. -public sealed class SimpleRecord +public sealed class SimpleRecord : TestRecord { public const int DimensionCount = 3; - [VectorStoreKey(StorageName = "key")] - public TKey Id { get; set; } = default!; - [VectorStoreData(StorageName = "text")] public string? Text { get; set; } @@ -29,7 +27,7 @@ public sealed class SimpleRecord public void AssertEqual(SimpleRecord? other, bool includeVectors, bool compareVectors) { Assert.NotNull(other); - Assert.Equal(this.Id, other.Id); + Assert.Equal(this.Key, other.Key); Assert.Equal(this.Text, other.Text); Assert.Equal(this.Number, other.Number); @@ -47,4 +45,7 @@ public void AssertEqual(SimpleRecord? other, bool includeVectors, bool com Assert.Equal(0, other.Floats.Length); } } + + public override string ToString() + => $"Key: {this.Key}, Text: {this.Text}"; } diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/Support/DynamicDataModelFixture.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/DynamicDataModelFixture.cs index ddb951382ec7..e86964474103 100644 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/Support/DynamicDataModelFixture.cs +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/DynamicDataModelFixture.cs @@ -4,7 +4,7 @@ namespace VectorData.ConformanceTests.Support; -public abstract class DynamicDataModelFixture : VectorStoreCollectionFixture> +public abstract class DynamicDataModelFixture : VectorStoreCollectionFixtureBase> { public const string KeyPropertyName = "key"; public const string StringPropertyName = "text"; diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/Support/DynamicVectorStoreCollectionFixture.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/DynamicVectorStoreCollectionFixture.cs new file mode 100644 index 000000000000..6e33a54adf98 --- /dev/null +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/DynamicVectorStoreCollectionFixture.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft. All rights reserved. + +namespace VectorData.ConformanceTests.Support; + +public abstract class DynamicVectorStoreCollectionFixture : VectorStoreCollectionFixtureBase> + where TKey : notnull +{ + protected abstract string KeyPropertyName { get; } + + public virtual async Task ReseedAsync() + { + // TODO: Use filtering delete, https://github.com/microsoft/semantic-kernel/issues/11830 + + const int BatchSize = 100; + + List keys = []; + do + { + await foreach (var record in this.Collection.GetAsync(r => true, top: BatchSize)) + { + // TODO: We don't use batching delete because of https://github.com/microsoft/semantic-kernel/issues/13303 + await this.Collection.DeleteAsync((TKey)record[this.KeyPropertyName]!); + } + } while (keys.Count == BatchSize); + + await this.SeedAsync(); + } +} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/Support/SimpleModelFixture.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/SimpleModelFixture.cs index 01a3c7e96ebe..f8e99b0b9c23 100644 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/Support/SimpleModelFixture.cs +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/SimpleModelFixture.cs @@ -12,30 +12,30 @@ protected override List> BuildTestData() => [ new() { - Id = this.GenerateNextKey(), + Key = this.GenerateNextKey(), Number = 1, - Text = "UsedByGetTests", + Text = "foo", Floats = Enumerable.Repeat(0.1f, SimpleRecord.DimensionCount).ToArray() }, new() { - Id = this.GenerateNextKey(), + Key = this.GenerateNextKey(), Number = 2, - Text = "UsedByUpdateTests", + Text = "bar", Floats = Enumerable.Repeat(0.2f, SimpleRecord.DimensionCount).ToArray() }, new() { - Id = this.GenerateNextKey(), + Key = this.GenerateNextKey(), Number = 3, - Text = "UsedByDeleteTests", + Text = "baz", Floats = Enumerable.Repeat(0.3f, SimpleRecord.DimensionCount).ToArray() }, new() { - Id = this.GenerateNextKey(), + Key = this.GenerateNextKey(), Number = 4, - Text = "UsedByDeleteBatchTests", + Text = "foo", Floats = Enumerable.Repeat(0.4f, SimpleRecord.DimensionCount).ToArray() } ]; @@ -45,7 +45,7 @@ public override VectorStoreCollectionDefinition CreateRecordDefinition() { Properties = [ - new VectorStoreKeyProperty(nameof(SimpleRecord.Id), typeof(TKey)), + new VectorStoreKeyProperty(nameof(SimpleRecord.Key), typeof(TKey)), new VectorStoreVectorProperty(nameof(SimpleRecord.Floats), typeof(ReadOnlyMemory), SimpleRecord.DimensionCount) { DistanceFunction = this.DistanceFunction, diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/Support/TestRecord.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/TestRecord.cs new file mode 100644 index 000000000000..2df6b952a83a --- /dev/null +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/TestRecord.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Microsoft.Extensions.VectorData; + +namespace VectorData.ConformanceTests.Support; + +public abstract class TestRecord +{ + [VectorStoreKey] + public TKey Key { get; set; } = default!; +} diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/Support/TestStore.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/TestStore.cs index 5094cc215443..da7c6205a1a1 100644 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/Support/TestStore.cs +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/TestStore.cs @@ -98,6 +98,8 @@ public virtual async Task WaitForDataAsync( for (var i = 0; i < 200; i++) { + // Note that we very intentionally use SearchAsync and not filtering GetAsync, as we want to wait until the data is visible + // specifically via vector search (some databases may show data via filtering before they are indexed for vector search). var results = collection.SearchAsync( vector, top: recordCount is 0 ? 1 : recordCount, diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/Support/VectorStoreCollectionFixture.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/VectorStoreCollectionFixture.cs index 87251e5ab2b0..9ceafd703e4b 100644 --- a/dotnet/test/VectorData/VectorData.ConformanceTests/Support/VectorStoreCollectionFixture.cs +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/VectorStoreCollectionFixture.cs @@ -1,59 +1,24 @@ // Copyright (c) Microsoft. All rights reserved. -using Microsoft.Extensions.VectorData; - namespace VectorData.ConformanceTests.Support; -#pragma warning disable CA1721 // Property names should not match get methods - -/// -/// A test fixture that sets up a single collection in the test vector store, with a specific record definition -/// and test data. -/// -public abstract class VectorStoreCollectionFixture : VectorStoreFixture +public abstract class VectorStoreCollectionFixture : VectorStoreCollectionFixtureBase where TKey : notnull - where TRecord : class + where TRecord : TestRecord { - private List? _testData; - - public abstract VectorStoreCollectionDefinition CreateRecordDefinition(); - protected virtual List BuildTestData() => []; - - public virtual string CollectionName => Guid.NewGuid().ToString(); - protected virtual string DistanceFunction => this.TestStore.DefaultDistanceFunction; - protected virtual string IndexKind => this.TestStore.DefaultIndexKind; - - protected virtual VectorStoreCollection GetCollection() - => this.TestStore.DefaultVectorStore.GetCollection(this.CollectionName, this.CreateRecordDefinition()); - - public override async Task InitializeAsync() + public virtual async Task ReseedAsync() { - await base.InitializeAsync(); + // TODO: Use filtering delete, https://github.com/microsoft/semantic-kernel/issues/11830 - this.Collection = this.GetCollection(); + const int BatchSize = 100; - if (await this.Collection.CollectionExistsAsync()) + TKey[] keys; + do { - await this.Collection.EnsureCollectionDeletedAsync(); - } + keys = await this.Collection.GetAsync(r => true, top: BatchSize).Select(r => r.Key).ToArrayAsync(); + await this.Collection.DeleteAsync(keys); + } while (keys.Length == BatchSize); - await this.Collection.EnsureCollectionExistsAsync(); await this.SeedAsync(); } - - public virtual VectorStoreCollection Collection { get; private set; } = null!; - - public List TestData => this._testData ??= this.BuildTestData(); - - protected virtual async Task SeedAsync() - { - if (this.TestData.Count > 0) - { - await this.Collection.UpsertAsync(this.TestData); - await this.WaitForDataAsync(); - } - } - - protected virtual Task WaitForDataAsync() - => this.TestStore.WaitForDataAsync(this.Collection, recordCount: this.TestData.Count); } diff --git a/dotnet/test/VectorData/VectorData.ConformanceTests/Support/VectorStoreCollectionFixtureBase.cs b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/VectorStoreCollectionFixtureBase.cs new file mode 100644 index 000000000000..38191885362b --- /dev/null +++ b/dotnet/test/VectorData/VectorData.ConformanceTests/Support/VectorStoreCollectionFixtureBase.cs @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Microsoft.Extensions.VectorData; + +namespace VectorData.ConformanceTests.Support; + +#pragma warning disable CA1721 // Property names should not match get methods + +/// +/// A test fixture that sets up a single collection in the test vector store, with a specific record definition +/// and test data. +/// +public abstract class VectorStoreCollectionFixtureBase : VectorStoreFixture + where TKey : notnull + where TRecord : class +{ + private List? _testData; + + public abstract VectorStoreCollectionDefinition CreateRecordDefinition(); + protected virtual List BuildTestData() => []; + + public virtual string CollectionName => Guid.NewGuid().ToString(); + protected virtual string DistanceFunction => this.TestStore.DefaultDistanceFunction; + protected virtual string IndexKind => this.TestStore.DefaultIndexKind; + + protected virtual VectorStoreCollection GetCollection() + => this.TestStore.DefaultVectorStore.GetCollection(this.CollectionName, this.CreateRecordDefinition()); + + public override async Task InitializeAsync() + { + await base.InitializeAsync(); + + this.Collection = this.GetCollection(); + + if (await this.Collection.CollectionExistsAsync()) + { + await this.Collection.EnsureCollectionDeletedAsync(); + } + + await this.Collection.EnsureCollectionExistsAsync(); + await this.SeedAsync(); + } + + public virtual VectorStoreCollection Collection { get; private set; } = null!; + + public List TestData => this._testData ??= this.BuildTestData(); + + protected virtual async Task SeedAsync() + { + if (this.TestData.Count > 0) + { + await this.Collection.UpsertAsync(this.TestData); + await this.WaitForDataAsync(); + } + } + + protected virtual Task WaitForDataAsync() + => this.TestStore.WaitForDataAsync(this.Collection, recordCount: this.TestData.Count); +} diff --git a/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateBatchConformanceTests.cs b/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateBatchConformanceTests.cs deleted file mode 100644 index c6ed8b017d0c..000000000000 --- a/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateBatchConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.CRUD; -using Weaviate.ConformanceTests.Support; -using Xunit; - -namespace Weaviate.ConformanceTests.CRUD; - -public class WeaviateBatchConformanceTests_NamedVectors(WeaviateSimpleModelNamedVectorsFixture fixture) - : BatchConformanceTests(fixture), IClassFixture -{ -} - -public class WeaviateBatchConformanceTests_UnnamedVector(WeaviateSimpleModelUnnamedVectorFixture fixture) - : BatchConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateDynamicRecordConformanceTests.cs b/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateDynamicRecordConformanceTests.cs deleted file mode 100644 index 6a41ae4a3cde..000000000000 --- a/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateDynamicRecordConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.CRUD; -using Weaviate.ConformanceTests.Support; -using Xunit; - -namespace Weaviate.ConformanceTests.CRUD; - -public class WeaviateDynamicRecordConformanceTests_NamedVectors(WeaviateDynamicDataModelNamedVectorsFixture fixture) - : DynamicDataModelConformanceTests(fixture), IClassFixture -{ -} - -public class WeaviateDynamicRecordConformanceTests_UnnamedVector(WeaviateDynamicDataModelUnnamedVectorFixture fixture) - : DynamicDataModelConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateNoVectorConformanceTests.cs b/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateNoVectorConformanceTests.cs deleted file mode 100644 index 6e255e43fd4a..000000000000 --- a/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateNoVectorConformanceTests.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.CRUD; -using VectorData.ConformanceTests.Support; -using Weaviate.ConformanceTests.Support; -using Xunit; - -namespace Weaviate.ConformanceTests.CRUD; - -public class WeaviateNoVectorConformanceTests_NamedVectors(WeaviateNoVectorConformanceTests_NamedVectors.Fixture fixture) - : NoVectorConformanceTests(fixture), IClassFixture -{ - public new class Fixture : NoVectorConformanceTests.Fixture - { - public override TestStore TestStore => WeaviateTestStore.NamedVectorsInstance; - - /// - /// Weaviate collections must start with an uppercase letter. - /// - public override string CollectionName => "NoVectorNamedCollection"; - } -} diff --git a/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateRecordConformanceTests.cs b/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateRecordConformanceTests.cs deleted file mode 100644 index 69d47bd755fa..000000000000 --- a/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateRecordConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.CRUD; -using Weaviate.ConformanceTests.Support; -using Xunit; - -namespace Weaviate.ConformanceTests.CRUD; - -public class WeaviateRecordConformanceTests_NamedVectors(WeaviateSimpleModelNamedVectorsFixture fixture) - : RecordConformanceTests(fixture), IClassFixture -{ -} - -public class WeaviateRecordConformanceTests_UnnamedVector(WeaviateSimpleModelUnnamedVectorFixture fixture) - : RecordConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Weaviate.ConformanceTests/Collections/WeaviateCollectionConformanceTests.cs b/dotnet/test/VectorData/Weaviate.ConformanceTests/Collections/WeaviateCollectionConformanceTests.cs deleted file mode 100644 index a0f00b3e533d..000000000000 --- a/dotnet/test/VectorData/Weaviate.ConformanceTests/Collections/WeaviateCollectionConformanceTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using VectorData.ConformanceTests.Collections; -using Weaviate.ConformanceTests.Support; -using Xunit; - -namespace Weaviate.ConformanceTests.Collections; - -public class WeaviateCollectionConformanceTests_NamedVectors(WeaviateSimpleModelNamedVectorsFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} - -public class WeaviateCollectionConformanceTests_UnnamedVector(WeaviateSimpleModelUnnamedVectorFixture fixture) - : CollectionConformanceTests(fixture), IClassFixture -{ -} diff --git a/dotnet/test/VectorData/Weaviate.ConformanceTests/Filter/WeaviateBasicQueryTests.cs b/dotnet/test/VectorData/Weaviate.ConformanceTests/Filter/WeaviateBasicQueryTests.cs deleted file mode 100644 index ea9a165d17fa..000000000000 --- a/dotnet/test/VectorData/Weaviate.ConformanceTests/Filter/WeaviateBasicQueryTests.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.Extensions.VectorData; -using VectorData.ConformanceTests.Filter; -using VectorData.ConformanceTests.Support; -using Weaviate.ConformanceTests.Support; -using Xunit; - -namespace Weaviate.ConformanceTests.Filter; - -public class WeaviateBasicQueryTests(WeaviateBasicQueryTests.Fixture fixture) - : BasicQueryTests(fixture), IClassFixture -{ - #region Filter by null - - // Null-state indexing needs to be set up, but that's not supported yet (#10358). - // We could interact with Weaviate directly (not via the abstraction) to do this. - - public override Task Equal_with_null_reference_type() - => Assert.ThrowsAsync(base.Equal_with_null_reference_type); - - public override Task Equal_with_null_captured() - => Assert.ThrowsAsync(base.Equal_with_null_captured); - - public override Task NotEqual_with_null_captured() - => Assert.ThrowsAsync(base.NotEqual_with_null_captured); - - public override Task NotEqual_with_null_reference_type() - => Assert.ThrowsAsync(base.NotEqual_with_null_reference_type); - - public override Task Equal_int_property_with_null_nullable_int() - => Assert.ThrowsAsync(base.Equal_int_property_with_null_nullable_int); - - #endregion - - #region Not - - // Weaviate currently doesn't support NOT (https://github.com/weaviate/weaviate/issues/3683) - public override Task Not_over_And() - => Assert.ThrowsAsync(base.Not_over_And); - - public override Task Not_over_Or() - => Assert.ThrowsAsync(base.Not_over_Or); - - #endregion - - #region Unsupported Contains scenarios - - public override Task Contains_over_captured_string_array() - => Assert.ThrowsAsync(base.Contains_over_captured_string_array); - - public override Task Contains_over_inline_int_array() - => Assert.ThrowsAsync(base.Contains_over_inline_int_array); - - public override Task Contains_over_inline_string_array() - => Assert.ThrowsAsync(base.Contains_over_inline_int_array); - - public override Task Contains_over_inline_string_array_with_weird_chars() - => Assert.ThrowsAsync(base.Contains_over_inline_string_array_with_weird_chars); - - #endregion - - public new class Fixture : BasicQueryTests.QueryFixture - { - public override TestStore TestStore => WeaviateTestStore.NamedVectorsInstance; - } -} diff --git a/dotnet/test/VectorData/Weaviate.ConformanceTests/ModelTests/WeaviateBasicModelTests.cs b/dotnet/test/VectorData/Weaviate.ConformanceTests/ModelTests/WeaviateBasicModelTests.cs new file mode 100644 index 000000000000..3a9c3daaa341 --- /dev/null +++ b/dotnet/test/VectorData/Weaviate.ConformanceTests/ModelTests/WeaviateBasicModelTests.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft. All rights reserved. + +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Weaviate.ConformanceTests.Support; +using Xunit; + +namespace Weaviate.ConformanceTests.ModelTests; + +public class WeaviateBasicModelTests_NamedVectors(WeaviateBasicModelTests_NamedVectors.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => WeaviateTestStore.NamedVectorsInstance; + } +} + +public class WeaviateBasicModelTests_UnnamedVectors(WeaviateBasicModelTests_UnnamedVectors.Fixture fixture) + : BasicModelTests(fixture), IClassFixture +{ + public new class Fixture : BasicModelTests.Fixture + { + public override TestStore TestStore => WeaviateTestStore.UnnamedVectorInstance; + } +} diff --git a/dotnet/test/VectorData/Weaviate.ConformanceTests/ModelTests/WeaviateDynamicModelTests.cs b/dotnet/test/VectorData/Weaviate.ConformanceTests/ModelTests/WeaviateDynamicModelTests.cs new file mode 100644 index 000000000000..bc14160cc469 --- /dev/null +++ b/dotnet/test/VectorData/Weaviate.ConformanceTests/ModelTests/WeaviateDynamicModelTests.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft. All rights reserved. + +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Weaviate.ConformanceTests.Support; +using Xunit; + +namespace Weaviate.ConformanceTests.ModelTests; + +public class WeaviateDynamicModelTests_NamedVectors(WeaviateDynamicModelTests_NamedVectors.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public new class Fixture : DynamicModelTests.Fixture + { + public override TestStore TestStore => WeaviateTestStore.NamedVectorsInstance; + } +} + +public class WeaviateDynamicModelTests_UnnamedVectors(WeaviateDynamicModelTests_UnnamedVectors.Fixture fixture) + : DynamicModelTests(fixture), IClassFixture +{ + public new class Fixture : DynamicModelTests.Fixture + { + public override TestStore TestStore => WeaviateTestStore.UnnamedVectorInstance; + } +} diff --git a/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateNoDataConformanceTests.cs b/dotnet/test/VectorData/Weaviate.ConformanceTests/ModelTests/WeaviateNoDataModelTests.cs similarity index 52% rename from dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateNoDataConformanceTests.cs rename to dotnet/test/VectorData/Weaviate.ConformanceTests/ModelTests/WeaviateNoDataModelTests.cs index b27a8dba6366..9d4a73d4df27 100644 --- a/dotnet/test/VectorData/Weaviate.ConformanceTests/CRUD/WeaviateNoDataConformanceTests.cs +++ b/dotnet/test/VectorData/Weaviate.ConformanceTests/ModelTests/WeaviateNoDataModelTests.cs @@ -1,16 +1,16 @@ // Copyright (c) Microsoft. All rights reserved. -using VectorData.ConformanceTests.CRUD; +using VectorData.ConformanceTests.ModelTests; using VectorData.ConformanceTests.Support; using Weaviate.ConformanceTests.Support; using Xunit; -namespace Weaviate.ConformanceTests.CRUD; +namespace Weaviate.ConformanceTests.ModelTests; -public class WeaviateNoDataConformanceTests_NamedVectors(WeaviateNoDataConformanceTests_NamedVectors.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture +public class WeaviateNoDataModelTests_NamedVectors(WeaviateNoDataModelTests_NamedVectors.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture { - public new class Fixture : NoDataConformanceTests.Fixture + public new class Fixture : NoDataModelTests.Fixture { public override TestStore TestStore => WeaviateTestStore.NamedVectorsInstance; @@ -21,10 +21,10 @@ public class WeaviateNoDataConformanceTests_NamedVectors(WeaviateNoDataConforman } } -public class WeaviateNoDataConformanceTests_UnnamedVector(WeaviateNoDataConformanceTests_UnnamedVector.Fixture fixture) - : NoDataConformanceTests(fixture), IClassFixture +public class WeaviateNoDataModelTests_UnnamedVector(WeaviateNoDataModelTests_UnnamedVector.Fixture fixture) + : NoDataModelTests(fixture), IClassFixture { - public new class Fixture : NoDataConformanceTests.Fixture + public new class Fixture : NoDataModelTests.Fixture { public override TestStore TestStore => WeaviateTestStore.UnnamedVectorInstance; diff --git a/dotnet/test/VectorData/Weaviate.ConformanceTests/ModelTests/WeaviateNoVectorModelTests.cs b/dotnet/test/VectorData/Weaviate.ConformanceTests/ModelTests/WeaviateNoVectorModelTests.cs new file mode 100644 index 000000000000..0da3b16ea8ce --- /dev/null +++ b/dotnet/test/VectorData/Weaviate.ConformanceTests/ModelTests/WeaviateNoVectorModelTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using VectorData.ConformanceTests.ModelTests; +using VectorData.ConformanceTests.Support; +using Weaviate.ConformanceTests.Support; +using Xunit; + +namespace Weaviate.ConformanceTests.ModelTests; + +public class WeaviateNoVectorModelTests(WeaviateNoVectorModelTests.Fixture fixture) + : NoVectorModelTests(fixture), IClassFixture +{ + public new class Fixture : NoVectorModelTests.Fixture + { + public override TestStore TestStore => WeaviateTestStore.NamedVectorsInstance; + } +} diff --git a/dotnet/test/VectorData/Weaviate.ConformanceTests/WeaviateCollectionManagementTests.cs b/dotnet/test/VectorData/Weaviate.ConformanceTests/WeaviateCollectionManagementTests.cs new file mode 100644 index 000000000000..3c31cca719e7 --- /dev/null +++ b/dotnet/test/VectorData/Weaviate.ConformanceTests/WeaviateCollectionManagementTests.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. + +using VectorData.ConformanceTests; +using Weaviate.ConformanceTests.Support; +using Xunit; + +namespace Weaviate.ConformanceTests; + +public class WeaviateCollectionManagementTests_NamedVectors(WeaviateSimpleModelNamedVectorsFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} + +public class WeaviateCollectionManagementTests_UnnamedVector(WeaviateSimpleModelUnnamedVectorFixture fixture) + : CollectionManagementTests(fixture), IClassFixture +{ +} diff --git a/dotnet/test/VectorData/Weaviate.ConformanceTests/Filter/WeaviateBasicFilterTests.cs b/dotnet/test/VectorData/Weaviate.ConformanceTests/WeaviateFilterTests.cs similarity index 88% rename from dotnet/test/VectorData/Weaviate.ConformanceTests/Filter/WeaviateBasicFilterTests.cs rename to dotnet/test/VectorData/Weaviate.ConformanceTests/WeaviateFilterTests.cs index 34ba1fc416ae..491d8ba463de 100644 --- a/dotnet/test/VectorData/Weaviate.ConformanceTests/Filter/WeaviateBasicFilterTests.cs +++ b/dotnet/test/VectorData/Weaviate.ConformanceTests/WeaviateFilterTests.cs @@ -1,15 +1,15 @@ // Copyright (c) Microsoft. All rights reserved. using Microsoft.Extensions.VectorData; -using VectorData.ConformanceTests.Filter; +using VectorData.ConformanceTests; using VectorData.ConformanceTests.Support; using Weaviate.ConformanceTests.Support; using Xunit; -namespace Weaviate.ConformanceTests.Filter; +namespace Weaviate.ConformanceTests; -public class WeaviateBasicFilterTests(WeaviateBasicFilterTests.Fixture fixture) - : BasicFilterTests(fixture), IClassFixture +public class WeaviateFilterTests(WeaviateFilterTests.Fixture fixture) + : FilterTests(fixture), IClassFixture { #region Filter by null @@ -60,7 +60,7 @@ public override Task Contains_over_inline_string_array_with_weird_chars() #endregion - public new class Fixture : BasicFilterTests.Fixture + public new class Fixture : FilterTests.Fixture { public override TestStore TestStore => WeaviateTestStore.NamedVectorsInstance; }