Skip to content

Commit 3eb869e

Browse files
authored
.Net: [MEVD] More test cleanup (#13320)
Another batch of test cleanup work - this almost concludes what I have planned for the tests. * We no longer create any collections with GUID names; all collections have a manually-defined name, and are deleted when a test starts running. This ensures that no collections are left behind if a test crashes or is stopped in the middle, and makes it easier to examine the database. * Removed global SimpleRecord and SimpleFixture, each test suite now has its own record and fixture. * Cleaned up and renamed DistanceFunctionTests to only focus on testing the different distance functions, and added corresponding tests elsewhere. * Added IndexKindTests to specifically cover different index types.
1 parent 802efdc commit 3eb869e

File tree

81 files changed

+1092
-1273
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1092
-1273
lines changed

dotnet/src/VectorData/AzureAISearch/AzureAISearchCollectionCreateMapping.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,10 @@ public static (VectorSearchField vectorSearchField, VectorSearchAlgorithmConfigu
7676
{
7777
IndexKind.Hnsw => new HnswAlgorithmConfiguration(algorithmConfigName) { Parameters = new HnswParameters { Metric = algorithmMetric } },
7878
IndexKind.Flat => new ExhaustiveKnnAlgorithmConfiguration(algorithmConfigName) { Parameters = new ExhaustiveKnnParameters { Metric = algorithmMetric } },
79-
_ => throw new InvalidOperationException($"Index kind '{indexKind}' on {nameof(VectorStoreVectorProperty)} '{vectorProperty.ModelName}' is not supported by the Azure AI Search VectorStore.")
79+
80+
_ => throw new NotSupportedException($"Index kind '{indexKind}' on {nameof(VectorStoreVectorProperty)} '{vectorProperty.ModelName}' is not supported by the Azure AI Search VectorStore.")
8081
};
82+
8183
var vectorSearchProfile = new VectorSearchProfile(vectorSearchProfileName, algorithmConfigName);
8284

8385
return (new VectorSearchField(vectorProperty.StorageName, vectorProperty.Dimensions, vectorSearchProfileName), algorithmConfiguration, vectorSearchProfile);
@@ -105,7 +107,8 @@ public static VectorSearchAlgorithmMetric GetSDKDistanceAlgorithm(VectorProperty
105107
DistanceFunction.CosineSimilarity or null => VectorSearchAlgorithmMetric.Cosine,
106108
DistanceFunction.DotProductSimilarity => VectorSearchAlgorithmMetric.DotProduct,
107109
DistanceFunction.EuclideanDistance => VectorSearchAlgorithmMetric.Euclidean,
108-
_ => throw new InvalidOperationException($"Distance function '{vectorProperty.DistanceFunction}' for {nameof(VectorStoreVectorProperty)} '{vectorProperty.ModelName}' is not supported by the Azure AI Search VectorStore.")
110+
111+
_ => throw new NotSupportedException($"Distance function '{vectorProperty.DistanceFunction}' for {nameof(VectorStoreVectorProperty)} '{vectorProperty.ModelName}' is not supported by the Azure AI Search VectorStore.")
109112
};
110113

111114
/// <summary>
@@ -142,6 +145,6 @@ public static SearchFieldDataType GetSDKFieldDataType(Type propertyType)
142145
Type t when t == typeof(DateTimeOffset[]) => SearchFieldDataType.Collection(SearchFieldDataType.DateTimeOffset),
143146
Type t when t == typeof(List<DateTimeOffset>) => SearchFieldDataType.Collection(SearchFieldDataType.DateTimeOffset),
144147

145-
_ => throw new InvalidOperationException($"Data type '{propertyType}' for {nameof(VectorStoreDataProperty)} is not supported by the Azure AI Search VectorStore.")
148+
_ => throw new NotSupportedException($"Data type '{propertyType}' for {nameof(VectorStoreDataProperty)} is not supported by the Azure AI Search VectorStore.")
146149
};
147150
}

dotnet/src/VectorData/CosmosNoSql/CosmosNoSqlCollection.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -773,21 +773,14 @@ private static VectorIndexType GetIndexKind(string? indexKind, string vectorProp
773773
/// More information about Azure CosmosDB NoSQL distance functions here: <see href="https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/vector-search#container-vector-policies" />.
774774
/// </summary>
775775
private static DistanceFunction GetDistanceFunction(string? distanceFunction, string vectorPropertyName)
776-
{
777-
if (string.IsNullOrWhiteSpace(distanceFunction))
778-
{
779-
// Use default distance function.
780-
return DistanceFunction.Cosine;
781-
}
782-
783-
return distanceFunction switch
776+
=> distanceFunction switch
784777
{
785-
SKDistanceFunction.CosineSimilarity => DistanceFunction.Cosine,
778+
SKDistanceFunction.CosineSimilarity or null => DistanceFunction.Cosine,
786779
SKDistanceFunction.DotProductSimilarity => DistanceFunction.DotProduct,
787780
SKDistanceFunction.EuclideanDistance => DistanceFunction.Euclidean,
788-
_ => throw new InvalidOperationException($"Distance function '{distanceFunction}' for {nameof(VectorStoreVectorProperty)} '{vectorPropertyName}' is not supported by the Azure CosmosDB NoSQL VectorStore.")
781+
782+
_ => throw new NotSupportedException($"Distance function '{distanceFunction}' for {nameof(VectorStoreVectorProperty)} '{vectorPropertyName}' is not supported by the Azure CosmosDB NoSQL VectorStore.")
789783
};
790-
}
791784

792785
/// <summary>
793786
/// Returns <see cref="VectorDataType"/> based on vector property type.

dotnet/src/VectorData/MongoDB/MongoCollectionCreateMapping.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ private static string GetDistanceFunction(string? distanceFunction, string vecto
9696
DistanceFunction.CosineSimilarity or null => "cosine",
9797
DistanceFunction.DotProductSimilarity => "dotProduct",
9898
DistanceFunction.EuclideanDistance => "euclidean",
99-
_ => throw new InvalidOperationException($"Distance function '{distanceFunction}' for {nameof(VectorStoreVectorProperty)} '{vectorPropertyName}' is not supported by the MongoDB VectorStore.")
99+
100+
_ => throw new NotSupportedException($"Distance function '{distanceFunction}' for {nameof(VectorStoreVectorProperty)} '{vectorPropertyName}' is not supported by the MongoDB VectorStore.")
100101
};
101102
}

dotnet/src/VectorData/Pinecone/PineconeCollection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ public override async Task EnsureCollectionExistsAsync(CancellationToken cancell
125125

126126
if (!string.IsNullOrEmpty(vectorProperty.IndexKind) && vectorProperty.IndexKind != "PGA")
127127
{
128-
throw new InvalidOperationException(
128+
throw new NotSupportedException(
129129
$"IndexKind of '{vectorProperty.IndexKind}' for property '{vectorProperty.ModelName}' is not supported. Pinecone only supports 'PGA' (Pinecone Graph Algorithm), which is always enabled.");
130130
}
131131

dotnet/src/VectorData/Qdrant/QdrantCollectionCreateMapping.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public static VectorParams MapSingleVector(VectorPropertyModel vectorProperty)
5858
{
5959
if (vectorProperty!.IndexKind is not null && vectorProperty!.IndexKind != IndexKind.Hnsw)
6060
{
61-
throw new InvalidOperationException($"Index kind '{vectorProperty!.IndexKind}' for {nameof(VectorStoreVectorProperty)} '{vectorProperty.ModelName}' is not supported by the Qdrant VectorStore.");
61+
throw new NotSupportedException($"Index kind '{vectorProperty!.IndexKind}' for {nameof(VectorStoreVectorProperty)} '{vectorProperty.ModelName}' is not supported by the Qdrant VectorStore.");
6262
}
6363

6464
return new VectorParams { Size = (ulong)vectorProperty.Dimensions, Distance = QdrantCollectionCreateMapping.GetSDKDistanceAlgorithm(vectorProperty) };
@@ -98,6 +98,6 @@ public static Distance GetSDKDistanceAlgorithm(VectorPropertyModel vectorPropert
9898
DistanceFunction.EuclideanDistance => Distance.Euclid,
9999
DistanceFunction.ManhattanDistance => Distance.Manhattan,
100100

101-
_ => throw new InvalidOperationException($"Distance function '{vectorProperty.DistanceFunction}' for {nameof(VectorStoreVectorProperty)} '{vectorProperty.ModelName}' is not supported by the Qdrant VectorStore.")
101+
_ => throw new NotSupportedException($"Distance function '{vectorProperty.DistanceFunction}' for {nameof(VectorStoreVectorProperty)} '{vectorProperty.ModelName}' is not supported by the Qdrant VectorStore.")
102102
};
103103
}

dotnet/src/VectorData/Redis/RedisCollectionCreateMapping.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ public static string GetSDKDistanceAlgorithm(VectorPropertyModel vectorProperty)
161161
DistanceFunction.CosineDistance => "COSINE",
162162
DistanceFunction.DotProductSimilarity => "IP",
163163
DistanceFunction.EuclideanSquaredDistance => "L2",
164-
_ => throw new InvalidOperationException($"Distance function '{vectorProperty.DistanceFunction}' for {nameof(VectorStoreVectorProperty)} '{vectorProperty.ModelName}' is not supported by the Redis VectorStore.")
164+
165+
_ => throw new NotSupportedException($"Distance function '{vectorProperty.DistanceFunction}' for {nameof(VectorStoreVectorProperty)} '{vectorProperty.ModelName}' is not supported by the Redis VectorStore.")
165166
};
166167

167168
/// <summary>

dotnet/test/VectorData/AzureAISearch.ConformanceTests/AzureAISearchDependencyInjectionTests.cs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66
using Microsoft.Extensions.DependencyInjection;
77
using Microsoft.SemanticKernel.Connectors.AzureAISearch;
88
using VectorData.ConformanceTests;
9-
using VectorData.ConformanceTests.Models;
109
using Xunit;
1110

1211
namespace AzureAISearch.ConformanceTests;
1312

1413
public class AzureAISearchDependencyInjectionTests
15-
: DependencyInjectionTests<AzureAISearchVectorStore, AzureAISearchCollection<string, SimpleRecord<string>>, string, SimpleRecord<string>>
14+
: DependencyInjectionTests<AzureAISearchVectorStore, AzureAISearchCollection<string, DependencyInjectionTests<string>.Record>, string, DependencyInjectionTests<string>.Record>
1615
{
1716
private static readonly Uri s_endpoint = new("https://localhost");
1817
private static readonly AzureKeyCredential s_keyCredential = new("fakeKey");
@@ -36,24 +35,24 @@ private static AzureKeyCredential KeyProvider(IServiceProvider sp, object? servi
3635
{
3736
yield return (services, serviceKey, name, lifetime) => serviceKey is null
3837
? services
39-
.AddAzureAISearchCollection<SimpleRecord<string>>(name,
38+
.AddAzureAISearchCollection<Record>(name,
4039
sp => new SearchIndexClient(EndpointProvider(sp), KeyProvider(sp)), lifetime: lifetime)
4140
: services
42-
.AddKeyedAzureAISearchCollection<SimpleRecord<string>>(serviceKey, name,
41+
.AddKeyedAzureAISearchCollection<Record>(serviceKey, name,
4342
sp => new SearchIndexClient(EndpointProvider(sp, serviceKey), KeyProvider(sp, serviceKey)), lifetime: lifetime);
4443

4544
yield return (services, serviceKey, name, lifetime) => serviceKey is null
4645
? services
4746
.AddSingleton<SearchIndexClient>(sp => new SearchIndexClient(s_endpoint, s_keyCredential))
48-
.AddAzureAISearchCollection<SimpleRecord<string>>(name, lifetime: lifetime)
47+
.AddAzureAISearchCollection<Record>(name, lifetime: lifetime)
4948
: services
5049
.AddSingleton<SearchIndexClient>(sp => new SearchIndexClient(s_endpoint, s_keyCredential))
51-
.AddKeyedAzureAISearchCollection<SimpleRecord<string>>(serviceKey, name, lifetime: lifetime);
50+
.AddKeyedAzureAISearchCollection<Record>(serviceKey, name, lifetime: lifetime);
5251

5352
yield return (services, serviceKey, name, lifetime) => serviceKey is null
54-
? services.AddAzureAISearchCollection<SimpleRecord<string>>(
53+
? services.AddAzureAISearchCollection<Record>(
5554
name, s_endpoint, s_keyCredential, lifetime: lifetime)
56-
: services.AddKeyedAzureAISearchCollection<SimpleRecord<string>>(
55+
: services.AddKeyedAzureAISearchCollection<Record>(
5756
serviceKey, name, s_endpoint, s_keyCredential, lifetime: lifetime);
5857
}
5958
}
@@ -89,9 +88,9 @@ public void EndpointCantBeNull()
8988
{
9089
IServiceCollection services = new ServiceCollection();
9190

92-
Assert.Throws<ArgumentNullException>(() => services.AddAzureAISearchCollection<SimpleRecord<string>>(
91+
Assert.Throws<ArgumentNullException>(() => services.AddAzureAISearchCollection<Record>(
9392
name: "notNull", endpoint: null!, s_keyCredential));
94-
Assert.Throws<ArgumentNullException>(() => services.AddKeyedAzureAISearchCollection<SimpleRecord<string>>(
93+
Assert.Throws<ArgumentNullException>(() => services.AddKeyedAzureAISearchCollection<Record>(
9594
serviceKey: "notNull", name: "notNull", endpoint: null!, s_keyCredential));
9695
}
9796

@@ -100,9 +99,9 @@ public void KeyCredentialCantBeNull()
10099
{
101100
IServiceCollection services = new ServiceCollection();
102101

103-
Assert.Throws<ArgumentNullException>(() => services.AddAzureAISearchCollection<SimpleRecord<string>>(
102+
Assert.Throws<ArgumentNullException>(() => services.AddAzureAISearchCollection<Record>(
104103
name: "notNull", s_endpoint, keyCredential: null!));
105-
Assert.Throws<ArgumentNullException>(() => services.AddKeyedAzureAISearchCollection<SimpleRecord<string>>(
104+
Assert.Throws<ArgumentNullException>(() => services.AddKeyedAzureAISearchCollection<Record>(
106105
serviceKey: "notNull", name: "notNull", s_endpoint, keyCredential: null!));
107106
}
108107

@@ -111,9 +110,9 @@ public void TokenCredentialCantBeNull()
111110
{
112111
IServiceCollection services = new ServiceCollection();
113112

114-
Assert.Throws<ArgumentNullException>(() => services.AddAzureAISearchCollection<SimpleRecord<string>>(
113+
Assert.Throws<ArgumentNullException>(() => services.AddAzureAISearchCollection<Record>(
115114
name: "notNull", s_endpoint, tokenCredential: null!));
116-
Assert.Throws<ArgumentNullException>(() => services.AddKeyedAzureAISearchCollection<SimpleRecord<string>>(
115+
Assert.Throws<ArgumentNullException>(() => services.AddKeyedAzureAISearchCollection<Record>(
117116
serviceKey: "notNull", name: "notNull", s_endpoint, tokenCredential: null!));
118117
}
119118
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using AzureAISearch.ConformanceTests.Support;
4+
using VectorData.ConformanceTests;
5+
using VectorData.ConformanceTests.Support;
6+
using Xunit;
7+
8+
namespace AzureAISearch.ConformanceTests;
9+
10+
public class AzureAISearchDistanceFunctionTests(AzureAISearchDistanceFunctionTests.Fixture fixture)
11+
: DistanceFunctionTests<string>(fixture), IClassFixture<AzureAISearchDistanceFunctionTests.Fixture>
12+
{
13+
public override Task CosineDistance() => Assert.ThrowsAsync<NotSupportedException>(base.CosineDistance);
14+
public override Task NegativeDotProductSimilarity() => Assert.ThrowsAsync<NotSupportedException>(base.NegativeDotProductSimilarity);
15+
public override Task EuclideanSquaredDistance() => Assert.ThrowsAsync<NotSupportedException>(base.EuclideanSquaredDistance);
16+
public override Task HammingDistance() => Assert.ThrowsAsync<NotSupportedException>(base.HammingDistance);
17+
public override Task ManhattanDistance() => Assert.ThrowsAsync<NotSupportedException>(base.ManhattanDistance);
18+
19+
public new class Fixture() : DistanceFunctionTests<string>.Fixture
20+
{
21+
public override string CollectionName => "distance-functions-" + AzureAISearchTestEnvironment.TestIndexPostfix;
22+
23+
public override TestStore TestStore => AzureAISearchTestStore.Instance;
24+
25+
// AzureAISearch does not return the expected standard mathematical result for each distance function
26+
public override bool AssertScores => false;
27+
}
28+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using AzureAISearch.ConformanceTests.Support;
4+
using Microsoft.Extensions.VectorData;
5+
using VectorData.ConformanceTests;
6+
using VectorData.ConformanceTests.Support;
7+
using VectorData.ConformanceTests.Xunit;
8+
using Xunit;
9+
10+
namespace AzureAISearch.ConformanceTests;
11+
12+
public class AzureAISearchIndexKindTests(AzureAISearchIndexKindTests.Fixture fixture)
13+
: IndexKindTests<string>(fixture), IClassFixture<AzureAISearchIndexKindTests.Fixture>
14+
{
15+
[ConditionalFact]
16+
public virtual Task Hnsw()
17+
=> this.Test(IndexKind.Hnsw);
18+
19+
public new class Fixture() : IndexKindTests<string>.Fixture
20+
{
21+
public override string CollectionName => "index-kind-" + AzureAISearchTestEnvironment.TestIndexPostfix;
22+
23+
public override TestStore TestStore => AzureAISearchTestStore.Instance;
24+
}
25+
}
Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

33
using VectorData.ConformanceTests;
4-
using VectorData.ConformanceTests.VectorSearch;
54

65
namespace AzureAISearch.ConformanceTests;
76

8-
public class AzureAISearchTestSuiteImplementationTests : TestSuiteImplementationTests
9-
{
10-
protected override ICollection<Type> IgnoredTestBases { get; } =
11-
[
12-
typeof(VectorSearchDistanceFunctionComplianceTests<>),
13-
typeof(VectorSearchWithFilterConformanceTests<>),
14-
];
15-
}
7+
public class AzureAISearchTestSuiteImplementationTests : TestSuiteImplementationTests;

0 commit comments

Comments
 (0)