chore: import upstream snapshot with attribution
This commit is contained in:
@@ -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<string>(fixture), IClassFixture<MongoBasicModelTests.Fixture>
|
||||
{
|
||||
public new class Fixture : BasicModelTests<string>.Fixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
}
|
||||
@@ -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<string>(fixture), IClassFixture<MongoDynamicModelTests.Fixture>
|
||||
{
|
||||
public new class Fixture : DynamicModelTests<string>.Fixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
}
|
||||
+17
@@ -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 MongoMultiVectorModelTests(MongoMultiVectorModelTests.Fixture fixture)
|
||||
: MultiVectorModelTests<string>(fixture), IClassFixture<MongoMultiVectorModelTests.Fixture>
|
||||
{
|
||||
public new class Fixture : MultiVectorModelTests<string>.Fixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
}
|
||||
@@ -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<string>(fixture), IClassFixture<MongoNoDataModelTests.Fixture>
|
||||
{
|
||||
public new class Fixture : NoDataModelTests<string>.Fixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
}
|
||||
+17
@@ -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<string>(fixture), IClassFixture<MongoNoVectorModelTests.Fixture>
|
||||
{
|
||||
public new class Fixture : NoVectorModelTests<string>.Fixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.VectorData;
|
||||
using Microsoft.SemanticKernel.Connectors.MongoDB;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using MongoDB.ConformanceTests.Support;
|
||||
using VectorData.ConformanceTests.Support;
|
||||
using VectorData.ConformanceTests.Xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace MongoDB.ConformanceTests;
|
||||
|
||||
public sealed class MongoBsonMappingTests(MongoBsonMappingTests.Fixture fixture)
|
||||
: IClassFixture<MongoBsonMappingTests.Fixture>
|
||||
{
|
||||
[ConditionalFact]
|
||||
public async Task Upsert_with_bson_model_works()
|
||||
{
|
||||
var store = (MongoTestStore)fixture.TestStore;
|
||||
var collectionName = fixture.TestStore.AdjustCollectionName("BsonModel");
|
||||
|
||||
var definition = new VectorStoreCollectionDefinition
|
||||
{
|
||||
Properties =
|
||||
[
|
||||
new VectorStoreKeyProperty(nameof(BsonTestModel.Id), typeof(string)),
|
||||
new VectorStoreDataProperty(nameof(BsonTestModel.HotelName), typeof(string))
|
||||
]
|
||||
};
|
||||
|
||||
var model = new BsonTestModel { Id = "key", HotelName = "Test Name" };
|
||||
|
||||
using var collection = new MongoCollection<string, BsonTestModel>(
|
||||
store.Database,
|
||||
collectionName,
|
||||
new() { Definition = definition });
|
||||
|
||||
await collection.EnsureCollectionExistsAsync();
|
||||
|
||||
try
|
||||
{
|
||||
await collection.UpsertAsync(model);
|
||||
var getResult = await collection.GetAsync(model.Id!);
|
||||
|
||||
Assert.NotNull(getResult);
|
||||
Assert.Equal("key", getResult!.Id);
|
||||
Assert.Equal("Test Name", getResult.HotelName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await collection.EnsureCollectionDeletedAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task Upsert_with_bson_vector_store_model_works()
|
||||
{
|
||||
var store = (MongoTestStore)fixture.TestStore;
|
||||
var collectionName = fixture.TestStore.AdjustCollectionName("BsonVectorStoreModel");
|
||||
|
||||
var model = new BsonVectorStoreTestModel { HotelId = "key", HotelName = "Test Name" };
|
||||
|
||||
using var collection = new MongoCollection<string, BsonVectorStoreTestModel>(store.Database, collectionName);
|
||||
|
||||
await collection.EnsureCollectionExistsAsync();
|
||||
|
||||
try
|
||||
{
|
||||
await collection.UpsertAsync(model);
|
||||
var getResult = await collection.GetAsync(model.HotelId!);
|
||||
|
||||
Assert.NotNull(getResult);
|
||||
Assert.Equal("key", getResult!.HotelId);
|
||||
Assert.Equal("Test Name", getResult.HotelName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await collection.EnsureCollectionDeletedAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task Upsert_with_bson_vector_store_with_name_model_works()
|
||||
{
|
||||
var store = (MongoTestStore)fixture.TestStore;
|
||||
var collectionName = fixture.TestStore.AdjustCollectionName("BsonVectorStoreWithNameModel");
|
||||
|
||||
var model = new BsonVectorStoreWithNameTestModel { Id = "key", HotelName = "Test Name" };
|
||||
|
||||
using var collection = new MongoCollection<string, BsonVectorStoreWithNameTestModel>(store.Database, collectionName);
|
||||
|
||||
await collection.EnsureCollectionExistsAsync();
|
||||
|
||||
try
|
||||
{
|
||||
await collection.UpsertAsync(model);
|
||||
var getResult = await collection.GetAsync(model.Id!);
|
||||
|
||||
Assert.NotNull(getResult);
|
||||
Assert.Equal("key", getResult!.Id);
|
||||
Assert.Equal("Test Name", getResult.HotelName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await collection.EnsureCollectionDeletedAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Fixture : VectorStoreFixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
|
||||
private sealed class BsonTestModel
|
||||
{
|
||||
[BsonId]
|
||||
public string? Id { get; set; }
|
||||
|
||||
[BsonElement("hotel_name")]
|
||||
public string? HotelName { get; set; }
|
||||
}
|
||||
|
||||
private sealed class BsonVectorStoreTestModel
|
||||
{
|
||||
[BsonId]
|
||||
[VectorStoreKey]
|
||||
public string? HotelId { get; set; }
|
||||
|
||||
[BsonElement("hotel_name")]
|
||||
[VectorStoreData]
|
||||
public string? HotelName { get; set; }
|
||||
}
|
||||
|
||||
private sealed class BsonVectorStoreWithNameTestModel
|
||||
{
|
||||
[BsonId]
|
||||
[VectorStoreKey]
|
||||
public string? Id { get; set; }
|
||||
|
||||
[BsonElement("bson_hotel_name")]
|
||||
[VectorStoreData(StorageName = "storage_hotel_name")]
|
||||
public string? HotelName { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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<string>(fixture), IClassFixture<MongoFixture>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net10.0;net472</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<IsPackable>false</IsPackable>
|
||||
<RootNamespace>MongoDB.ConformanceTests</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
|
||||
<PackageReference Include="xunit" />
|
||||
<PackageReference Include="xunit.runner.visualstudio">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
<PackageReference Include="Testcontainers.MongoDB" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\VectorData\MongoDB\MongoDB.csproj" />
|
||||
<ProjectReference Include="..\VectorData.ConformanceTests\VectorData.ConformanceTests.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.SemanticKernel.Connectors.MongoDB;
|
||||
using MongoDB.Driver;
|
||||
using VectorData.ConformanceTests;
|
||||
using Xunit;
|
||||
|
||||
namespace MongoDB.ConformanceTests;
|
||||
|
||||
public class MongoDependencyInjectionTests
|
||||
: DependencyInjectionTests<MongoVectorStore, MongoCollection<string, DependencyInjectionTests<string>.Record>, string, DependencyInjectionTests<string>.Record>
|
||||
{
|
||||
protected const string ConnectionString = "mongodb://localhost:27017";
|
||||
protected const string DatabaseName = "dbName";
|
||||
|
||||
protected override void PopulateConfiguration(ConfigurationManager configuration, object? serviceKey = null)
|
||||
=> configuration.AddInMemoryCollection(
|
||||
[
|
||||
new(CreateConfigKey("Mongo", serviceKey, "ConnectionString"), ConnectionString),
|
||||
new(CreateConfigKey("Mongo", serviceKey, "DatabaseName"), DatabaseName),
|
||||
]);
|
||||
|
||||
private static string ConnectionStringProvider(IServiceProvider sp)
|
||||
=> sp.GetRequiredService<IConfiguration>().GetRequiredSection("Mongo:ConnectionString").Value!;
|
||||
|
||||
private static string ConnectionStringProvider(IServiceProvider sp, object serviceKey)
|
||||
=> sp.GetRequiredService<IConfiguration>().GetRequiredSection(CreateConfigKey("Mongo", serviceKey, "ConnectionString")).Value!;
|
||||
|
||||
private static string DatabaseNameProvider(IServiceProvider sp)
|
||||
=> sp.GetRequiredService<IConfiguration>().GetRequiredSection("Mongo:DatabaseName").Value!;
|
||||
|
||||
private static string DatabaseNameProvider(IServiceProvider sp, object serviceKey)
|
||||
=> sp.GetRequiredService<IConfiguration>().GetRequiredSection(CreateConfigKey("Mongo", serviceKey, "DatabaseName")).Value!;
|
||||
|
||||
public override IEnumerable<Func<IServiceCollection, object?, string, ServiceLifetime, IServiceCollection>> CollectionDelegates
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return (services, serviceKey, name, lifetime) => serviceKey is null
|
||||
? services
|
||||
.AddSingleton<MongoClient>(sp => new MongoClient(MongoClientSettings.FromConnectionString(ConnectionString)))
|
||||
.AddSingleton<IMongoDatabase>(sp => sp.GetRequiredService<MongoClient>().GetDatabase(DatabaseName))
|
||||
.AddMongoCollection<Record>(name, lifetime: lifetime)
|
||||
: services
|
||||
.AddSingleton<MongoClient>(sp => new MongoClient(MongoClientSettings.FromConnectionString(ConnectionString)))
|
||||
.AddSingleton<IMongoDatabase>(sp => sp.GetRequiredService<MongoClient>().GetDatabase(DatabaseName))
|
||||
.AddKeyedMongoCollection<Record>(serviceKey, name, lifetime: lifetime);
|
||||
|
||||
yield return (services, serviceKey, name, lifetime) => serviceKey is null
|
||||
? services.AddMongoCollection<Record>(
|
||||
name, ConnectionString, DatabaseName, lifetime: lifetime)
|
||||
: services.AddKeyedMongoCollection<Record>(
|
||||
serviceKey, name, ConnectionString, DatabaseName, lifetime: lifetime);
|
||||
|
||||
yield return (services, serviceKey, name, lifetime) => serviceKey is null
|
||||
? services.AddMongoCollection<Record>(
|
||||
name, ConnectionStringProvider, DatabaseNameProvider, lifetime: lifetime)
|
||||
: services.AddKeyedMongoCollection<Record>(
|
||||
serviceKey, name, sp => ConnectionStringProvider(sp, serviceKey), sp => DatabaseNameProvider(sp, serviceKey), lifetime: lifetime);
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<Func<IServiceCollection, object?, ServiceLifetime, IServiceCollection>> StoreDelegates
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return (services, serviceKey, lifetime) => serviceKey is null
|
||||
? services.AddMongoVectorStore(
|
||||
ConnectionString, DatabaseName, lifetime: lifetime)
|
||||
: services.AddKeyedMongoVectorStore(
|
||||
serviceKey, ConnectionString, DatabaseName, lifetime: lifetime);
|
||||
|
||||
yield return (services, serviceKey, lifetime) => serviceKey is null
|
||||
? services
|
||||
.AddSingleton<MongoClient>(sp => new MongoClient(MongoClientSettings.FromConnectionString(ConnectionString)))
|
||||
.AddSingleton<IMongoDatabase>(sp => sp.GetRequiredService<MongoClient>().GetDatabase(DatabaseName))
|
||||
.AddMongoVectorStore(lifetime: lifetime)
|
||||
: services
|
||||
.AddSingleton<MongoClient>(sp => new MongoClient(MongoClientSettings.FromConnectionString(ConnectionString)))
|
||||
.AddSingleton<IMongoDatabase>(sp => sp.GetRequiredService<MongoClient>().GetDatabase(DatabaseName))
|
||||
.AddKeyedMongoVectorStore(serviceKey, lifetime: lifetime);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConnectionStringProviderCantBeNull()
|
||||
{
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddMongoCollection<Record>(
|
||||
name: "notNull", connectionStringProvider: null!, databaseNameProvider: DatabaseNameProvider));
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddKeyedMongoCollection<Record>(
|
||||
serviceKey: "notNull", name: "notNull", connectionStringProvider: null!, databaseNameProvider: DatabaseNameProvider));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatabaseNameProviderCantBeNull()
|
||||
{
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddMongoCollection<Record>(
|
||||
name: "notNull", connectionStringProvider: ConnectionStringProvider, databaseNameProvider: null!));
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddKeyedMongoCollection<Record>(
|
||||
serviceKey: "notNull", name: "notNull", connectionStringProvider: ConnectionStringProvider, databaseNameProvider: null!));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConnectionStringCantBeNullOrEmpty()
|
||||
{
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddMongoVectorStore(connectionString: null!, DatabaseName));
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddKeyedMongoVectorStore(serviceKey: "notNull", connectionString: null!, DatabaseName));
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddMongoCollection<Record>(
|
||||
name: "notNull", connectionString: null!, DatabaseName));
|
||||
Assert.Throws<ArgumentException>(() => services.AddMongoCollection<Record>(
|
||||
name: "notNull", connectionString: "", DatabaseName));
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddKeyedMongoCollection<Record>(
|
||||
serviceKey: "notNull", name: "notNull", connectionString: null!, DatabaseName));
|
||||
Assert.Throws<ArgumentException>(() => services.AddKeyedMongoCollection<Record>(
|
||||
serviceKey: "notNull", name: "notNull", connectionString: "", DatabaseName));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatabaseNameCantBeNullOrEmpty()
|
||||
{
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddMongoVectorStore(ConnectionString, databaseName: null!));
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddKeyedMongoVectorStore(serviceKey: "notNull", ConnectionString, databaseName: null!));
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddMongoCollection<Record>(
|
||||
name: "notNull", ConnectionString, databaseName: null!));
|
||||
Assert.Throws<ArgumentException>(() => services.AddMongoCollection<Record>(
|
||||
name: "notNull", ConnectionString, databaseName: ""));
|
||||
Assert.Throws<ArgumentNullException>(() => services.AddKeyedMongoCollection<Record>(
|
||||
serviceKey: "notNull", name: "notNull", ConnectionString, databaseName: null!));
|
||||
Assert.Throws<ArgumentException>(() => services.AddKeyedMongoCollection<Record>(
|
||||
serviceKey: "notNull", name: "notNull", ConnectionString, databaseName: ""));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using MongoDB.ConformanceTests.Support;
|
||||
using VectorData.ConformanceTests;
|
||||
using VectorData.ConformanceTests.Support;
|
||||
using Xunit;
|
||||
|
||||
namespace MongoDB.ConformanceTests;
|
||||
|
||||
public class MongoDistanceFunctionTests(MongoDistanceFunctionTests.Fixture fixture)
|
||||
: DistanceFunctionTests<int>(fixture), IClassFixture<MongoDistanceFunctionTests.Fixture>
|
||||
{
|
||||
public override Task CosineDistance() => Assert.ThrowsAsync<NotSupportedException>(base.CosineDistance);
|
||||
public override Task EuclideanSquaredDistance() => Assert.ThrowsAsync<NotSupportedException>(base.EuclideanSquaredDistance);
|
||||
public override Task NegativeDotProductSimilarity() => Assert.ThrowsAsync<NotSupportedException>(base.NegativeDotProductSimilarity);
|
||||
public override Task HammingDistance() => Assert.ThrowsAsync<NotSupportedException>(base.HammingDistance);
|
||||
public override Task ManhattanDistance() => Assert.ThrowsAsync<NotSupportedException>(base.ManhattanDistance);
|
||||
|
||||
public new class Fixture() : DistanceFunctionTests<int>.Fixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
|
||||
public override bool AssertScores { get; } = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.VectorData;
|
||||
using MongoDB.ConformanceTests.Support;
|
||||
using VectorData.ConformanceTests;
|
||||
using VectorData.ConformanceTests.Support;
|
||||
using Xunit;
|
||||
|
||||
namespace MongoDB.ConformanceTests;
|
||||
|
||||
public class MongoEmbeddingGenerationTests(MongoEmbeddingGenerationTests.StringVectorFixture stringVectorFixture, MongoEmbeddingGenerationTests.RomOfFloatVectorFixture romOfFloatVectorFixture)
|
||||
: EmbeddingGenerationTests<string>(stringVectorFixture, romOfFloatVectorFixture), IClassFixture<MongoEmbeddingGenerationTests.StringVectorFixture>, IClassFixture<MongoEmbeddingGenerationTests.RomOfFloatVectorFixture>
|
||||
{
|
||||
public new class StringVectorFixture : EmbeddingGenerationTests<string>.StringVectorFixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
|
||||
public override VectorStore CreateVectorStore(IEmbeddingGenerator? embeddingGenerator)
|
||||
=> MongoTestStore.Instance.GetVectorStore(new() { EmbeddingGenerator = embeddingGenerator });
|
||||
|
||||
public override Func<IServiceCollection, IServiceCollection>[] DependencyInjectionStoreRegistrationDelegates =>
|
||||
[
|
||||
services => services
|
||||
.AddSingleton(MongoTestStore.Instance.Database)
|
||||
.AddMongoVectorStore()
|
||||
];
|
||||
|
||||
public override Func<IServiceCollection, IServiceCollection>[] DependencyInjectionCollectionRegistrationDelegates =>
|
||||
[
|
||||
services => services
|
||||
.AddSingleton(MongoTestStore.Instance.Database)
|
||||
.AddMongoCollection<RecordWithAttributes>(this.CollectionName)
|
||||
];
|
||||
}
|
||||
|
||||
public new class RomOfFloatVectorFixture : EmbeddingGenerationTests<string>.RomOfFloatVectorFixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
|
||||
public override VectorStore CreateVectorStore(IEmbeddingGenerator? embeddingGenerator)
|
||||
=> MongoTestStore.Instance.GetVectorStore(new() { EmbeddingGenerator = embeddingGenerator });
|
||||
|
||||
public override Func<IServiceCollection, IServiceCollection>[] DependencyInjectionStoreRegistrationDelegates =>
|
||||
[
|
||||
services => services
|
||||
.AddSingleton(MongoTestStore.Instance.Database)
|
||||
.AddMongoVectorStore()
|
||||
];
|
||||
|
||||
public override Func<IServiceCollection, IServiceCollection>[] DependencyInjectionCollectionRegistrationDelegates =>
|
||||
[
|
||||
services => services
|
||||
.AddSingleton(MongoTestStore.Instance.Database)
|
||||
.AddMongoCollection<RecordWithAttributes>(this.CollectionName)
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
// 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<string>(fixture), IClassFixture<MongoFilterTests.Fixture>
|
||||
{
|
||||
// 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<NotSupportedException>(base.Equal_with_null_reference_type);
|
||||
|
||||
public override Task Equal_with_null_captured()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.Equal_with_null_captured);
|
||||
|
||||
public override Task NotEqual_with_null_reference_type()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.NotEqual_with_null_reference_type);
|
||||
|
||||
public override Task NotEqual_with_null_captured()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.NotEqual_with_null_captured);
|
||||
|
||||
public override Task Equal_int_property_with_null_nullable_int()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(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<NotSupportedException>(base.Not_over_And);
|
||||
|
||||
public override Task Not_over_Or()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.Not_over_Or);
|
||||
|
||||
#endregion
|
||||
|
||||
public override Task Contains_over_field_string_array()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.Contains_over_field_string_array);
|
||||
|
||||
public override Task Contains_over_field_string_List()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.Contains_over_field_string_List);
|
||||
|
||||
public override Task Contains_with_Enumerable_Contains()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.Contains_with_Enumerable_Contains);
|
||||
|
||||
#if !NETFRAMEWORK
|
||||
public override Task Contains_with_MemoryExtensions_Contains()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.Contains_with_MemoryExtensions_Contains);
|
||||
#endif
|
||||
|
||||
#if NET10_0_OR_GREATER
|
||||
[ConditionalFact]
|
||||
public override Task Contains_with_MemoryExtensions_Contains_with_null_comparer()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.Contains_with_MemoryExtensions_Contains_with_null_comparer);
|
||||
#endif
|
||||
|
||||
// Any with Contains over array fields not supported on MongoDB in vector search pre-filters
|
||||
public override Task Any_with_Contains_over_inline_string_array()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.Any_with_Contains_over_inline_string_array);
|
||||
|
||||
public override Task Any_with_Contains_over_captured_string_array()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.Any_with_Contains_over_captured_string_array);
|
||||
|
||||
public override Task Any_with_Contains_over_captured_string_list()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.Any_with_Contains_over_captured_string_list);
|
||||
|
||||
public override Task Any_over_List_with_Contains_over_captured_string_array()
|
||||
=> Assert.ThrowsAsync<NotSupportedException>(base.Any_over_List_with_Contains_over_captured_string_array);
|
||||
|
||||
public new class Fixture : FilterTests<string>.Fixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using MongoDB.ConformanceTests.Support;
|
||||
using VectorData.ConformanceTests;
|
||||
using VectorData.ConformanceTests.Support;
|
||||
using Xunit;
|
||||
|
||||
namespace MongoDB.ConformanceTests;
|
||||
|
||||
public class MongoHybridSearchTests(
|
||||
MongoHybridSearchTests.VectorAndStringFixture vectorAndStringFixture,
|
||||
MongoHybridSearchTests.MultiTextFixture multiTextFixture)
|
||||
: HybridSearchTests<string>(vectorAndStringFixture, multiTextFixture),
|
||||
IClassFixture<MongoHybridSearchTests.VectorAndStringFixture>,
|
||||
IClassFixture<MongoHybridSearchTests.MultiTextFixture>
|
||||
{
|
||||
public new class VectorAndStringFixture : HybridSearchTests<string>.VectorAndStringFixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
|
||||
public new class MultiTextFixture : HybridSearchTests<string>.MultiTextFixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using MongoDB.ConformanceTests.Support;
|
||||
using VectorData.ConformanceTests;
|
||||
using VectorData.ConformanceTests.Support;
|
||||
using Xunit;
|
||||
|
||||
namespace MongoDB.ConformanceTests;
|
||||
|
||||
public class MongoIndexKindTests(MongoIndexKindTests.Fixture fixture)
|
||||
: IndexKindTests<int>(fixture), IClassFixture<MongoIndexKindTests.Fixture>
|
||||
{
|
||||
public new class Fixture() : IndexKindTests<int>.Fixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using VectorData.ConformanceTests;
|
||||
|
||||
namespace MongoDB.ConformanceTests;
|
||||
|
||||
public class MongoTestSuiteImplementationTests : TestSuiteImplementationTests;
|
||||
@@ -0,0 +1,5 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using VectorData.ConformanceTests.Xunit;
|
||||
|
||||
[assembly: DisableTests(Skip = "The MongoDB container is intermittently timing out at startup time blocking prs, so these test should be run manually.")]
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using VectorData.ConformanceTests.Support;
|
||||
|
||||
namespace MongoDB.ConformanceTests.Support;
|
||||
|
||||
public class MongoFixture : VectorStoreFixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace MongoDB.ConformanceTests.Support;
|
||||
|
||||
#pragma warning disable CA1810 // Initialize all static fields when those fields are declared
|
||||
|
||||
internal static class MongoTestEnvironment
|
||||
{
|
||||
public static readonly string? ConnectionUrl;
|
||||
|
||||
public static bool IsConnectionInfoDefined => ConnectionUrl is not null;
|
||||
|
||||
static MongoTestEnvironment()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddJsonFile(path: "testsettings.json", optional: true)
|
||||
.AddJsonFile(path: "testsettings.development.json", optional: true)
|
||||
.AddEnvironmentVariables()
|
||||
.Build();
|
||||
|
||||
var mongoSection = configuration.GetSection("MongoDB");
|
||||
ConnectionUrl = mongoSection["ConnectionURL"];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using DotNet.Testcontainers.Builders;
|
||||
using DotNet.Testcontainers.Configurations;
|
||||
using DotNet.Testcontainers.Containers;
|
||||
using Microsoft.SemanticKernel.Connectors.MongoDB;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
using Testcontainers.MongoDb;
|
||||
using VectorData.ConformanceTests.Support;
|
||||
|
||||
namespace MongoDB.ConformanceTests.Support;
|
||||
|
||||
#pragma warning disable CA1001 // Type owns disposable fields but is not disposable
|
||||
|
||||
internal sealed class MongoTestStore : TestStore
|
||||
{
|
||||
public static MongoTestStore Instance { get; } = new();
|
||||
|
||||
private MongoDbContainer? _container;
|
||||
|
||||
public MongoClient? _client { get; private set; }
|
||||
public IMongoDatabase? _database { get; private set; }
|
||||
|
||||
public MongoClient Client => this._client ?? throw new InvalidOperationException("Not initialized");
|
||||
public IMongoDatabase Database => this._database ?? throw new InvalidOperationException("Not initialized");
|
||||
|
||||
public MongoVectorStore GetVectorStore(MongoVectorStoreOptions options)
|
||||
=> new(this.Database, options);
|
||||
|
||||
private MongoTestStore()
|
||||
{
|
||||
}
|
||||
|
||||
protected override async Task StartAsync()
|
||||
{
|
||||
var clientSettings = MongoTestEnvironment.IsConnectionInfoDefined
|
||||
? MongoClientSettings.FromConnectionString(MongoTestEnvironment.ConnectionUrl)
|
||||
: await this.StartMongoDbContainerAsync();
|
||||
|
||||
this._client = new MongoClient(clientSettings);
|
||||
this._database = this._client.GetDatabase("VectorSearchTests");
|
||||
this.DefaultVectorStore = new MongoVectorStore(this._database);
|
||||
}
|
||||
|
||||
private async Task<MongoClientSettings> StartMongoDbContainerAsync()
|
||||
{
|
||||
this._container = new MongoDbBuilder()
|
||||
.WithImage("mongodb/mongodb-atlas-local:7.0.6")
|
||||
.WithWaitStrategy(Wait.ForUnixContainer().AddCustomWaitStrategy(new MongoDbWaitUntil()))
|
||||
.Build();
|
||||
|
||||
using CancellationTokenSource cts = new();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(60));
|
||||
await this._container.StartAsync(cts.Token);
|
||||
|
||||
return new MongoClientSettings
|
||||
{
|
||||
Server = new MongoServerAddress(this._container.Hostname, this._container.GetMappedPublicPort(MongoDbBuilder.MongoDbPort)),
|
||||
DirectConnection = true,
|
||||
// ReadConcern = ReadConcern.Linearizable,
|
||||
// WriteConcern = WriteConcern.WMajority
|
||||
};
|
||||
}
|
||||
|
||||
private static readonly string? s_baseObjectId = ObjectId.GenerateNewId().ToString().Substring(0, 14);
|
||||
|
||||
public override TKey GenerateKey<TKey>(int value)
|
||||
{
|
||||
if (typeof(TKey) == typeof(ObjectId))
|
||||
{
|
||||
return (TKey)(object)ObjectId.Parse(s_baseObjectId + value.ToString("0000000000"));
|
||||
}
|
||||
|
||||
return base.GenerateKey<TKey>(value);
|
||||
}
|
||||
|
||||
protected override async Task StopAsync()
|
||||
{
|
||||
if (this._container != null)
|
||||
{
|
||||
await this._container.StopAsync();
|
||||
this._container = null;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class MongoDbWaitUntil : IWaitUntil
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> UntilAsync(IContainer container)
|
||||
{
|
||||
var (stdout, _) = await container.GetLogsAsync(timestampsEnabled: false)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return stdout.Contains("\"msg\":\"Waiting for connections\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using MongoDB.ConformanceTests.Support;
|
||||
using VectorData.ConformanceTests.Support;
|
||||
using VectorData.ConformanceTests.TypeTests;
|
||||
using Xunit;
|
||||
|
||||
namespace MongoDB.ConformanceTests.TypeTests;
|
||||
|
||||
public class MongoDataTypeTests(MongoDataTypeTests.Fixture fixture)
|
||||
: DataTypeTests<string, DataTypeTests<string>.DefaultRecord>(fixture), IClassFixture<MongoDataTypeTests.Fixture>
|
||||
{
|
||||
public override Task Decimal()
|
||||
=> this.Test<decimal>(
|
||||
"Decimal", 8.5m, 9.5m,
|
||||
isFilterable: false); // Operand type is not supported for $vectorSearch: decimal
|
||||
|
||||
public override Task DateTime()
|
||||
=> this.Test<DateTime>(
|
||||
"DateTime",
|
||||
new DateTime(2020, 1, 1, 12, 30, 45, DateTimeKind.Utc),
|
||||
new DateTime(2021, 2, 3, 13, 40, 55, DateTimeKind.Utc),
|
||||
instantiationExpression: () => new DateTime(2020, 1, 1, 12, 30, 45),
|
||||
isFilterable: false); // Operand type is not supported for $vectorSearch: date
|
||||
|
||||
// MongoDB stores DateTimeOffset as UTC BsonDateTime; the offset is lost on round-trip.
|
||||
public override Task DateTimeOffset()
|
||||
=> this.Test<DateTimeOffset>(
|
||||
"DateTimeOffset",
|
||||
new DateTimeOffset(2020, 1, 1, 12, 30, 45, TimeSpan.Zero),
|
||||
new DateTimeOffset(2021, 2, 3, 13, 40, 55, TimeSpan.Zero),
|
||||
instantiationExpression: () => new DateTimeOffset(2020, 1, 1, 12, 30, 45, TimeSpan.Zero),
|
||||
isFilterable: false); // Operand type is not supported for $vectorSearch: date
|
||||
|
||||
#if NET
|
||||
public override Task DateOnly()
|
||||
=> this.Test<DateOnly>(
|
||||
"DateOnly",
|
||||
new DateOnly(2020, 1, 1),
|
||||
new DateOnly(2021, 2, 3),
|
||||
isFilterable: false); // Operand type is not supported for $vectorSearch: date
|
||||
#endif
|
||||
|
||||
public override Task String_array()
|
||||
=> this.Test<string[]>(
|
||||
"StringArray",
|
||||
["foo", "bar"],
|
||||
["foo", "baz"],
|
||||
isFilterable: false); // Operand type is not supported for $vectorSearch: array
|
||||
|
||||
public new class Fixture : DataTypeTests<string, DataTypeTests<string>.DefaultRecord>.Fixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
|
||||
// MongoDB does not support null checks in vector search pre-filters
|
||||
public override bool IsNullFilteringSupported => false;
|
||||
|
||||
public override Type[] UnsupportedDefaultTypes { get; } =
|
||||
[
|
||||
typeof(byte),
|
||||
typeof(short),
|
||||
typeof(Guid),
|
||||
#if NET
|
||||
typeof(TimeOnly)
|
||||
#endif
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using MongoDB.ConformanceTests.Support;
|
||||
using VectorData.ConformanceTests.Support;
|
||||
using VectorData.ConformanceTests.TypeTests;
|
||||
using Xunit;
|
||||
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
|
||||
namespace MongoDB.ConformanceTests.TypeTests;
|
||||
|
||||
public class MongoEmbeddingTypeTests(MongoEmbeddingTypeTests.Fixture fixture)
|
||||
: EmbeddingTypeTests<string>(fixture), IClassFixture<MongoEmbeddingTypeTests.Fixture>
|
||||
{
|
||||
public new class Fixture : EmbeddingTypeTests<string>.Fixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.ConformanceTests.Support;
|
||||
using VectorData.ConformanceTests.Support;
|
||||
using VectorData.ConformanceTests.TypeTests;
|
||||
using VectorData.ConformanceTests.Xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace MongoDB.ConformanceTests.TypeTests;
|
||||
|
||||
public class MongoKeyTypeTests(MongoKeyTypeTests.Fixture fixture)
|
||||
: KeyTypeTests(fixture), IClassFixture<MongoKeyTypeTests.Fixture>
|
||||
{
|
||||
[ConditionalFact]
|
||||
public virtual Task ObjectId() => this.Test<ObjectId>(new("652f8c3e8f9b2c1a4d3e6a7b"), supportsAutoGeneration: true);
|
||||
|
||||
[ConditionalFact]
|
||||
public virtual Task String() => this.Test<string>("foo", "bar");
|
||||
|
||||
[ConditionalFact]
|
||||
public virtual Task Int() => this.Test<int>(8);
|
||||
|
||||
[ConditionalFact]
|
||||
public virtual Task Long() => this.Test<long>(8L);
|
||||
|
||||
public new class Fixture : KeyTypeTests.Fixture
|
||||
{
|
||||
public override TestStore TestStore => MongoTestStore.Instance;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user