chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:21:23 +08:00
commit b957a53def
5423 changed files with 863745 additions and 0 deletions
@@ -0,0 +1,145 @@
// Copyright (c) Microsoft. All rights reserved.
using CosmosMongoDB.ConformanceTests.Support;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Connectors.CosmosMongoDB;
using MongoDB.Bson.Serialization.Attributes;
using VectorData.ConformanceTests.Support;
using VectorData.ConformanceTests.Xunit;
using Xunit;
namespace CosmosMongoDB.ConformanceTests;
[CosmosConnectionStringRequired]
public sealed class CosmosMongoBsonMappingTests(CosmosMongoBsonMappingTests.Fixture fixture)
: IClassFixture<CosmosMongoBsonMappingTests.Fixture>
{
[ConditionalFact]
public async Task Upsert_with_bson_model_works()
{
var store = (CosmosMongoTestStore)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 CosmosMongoCollection<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 = (CosmosMongoTestStore)fixture.TestStore;
var collectionName = fixture.TestStore.AdjustCollectionName("BsonVectorStoreModel");
var model = new BsonVectorStoreTestModel { HotelId = "key", HotelName = "Test Name" };
using var collection = new CosmosMongoCollection<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 = (CosmosMongoTestStore)fixture.TestStore;
var collectionName = fixture.TestStore.AdjustCollectionName("BsonVectorStoreWithNameModel");
var model = new BsonVectorStoreWithNameTestModel { Id = "key", HotelName = "Test Name" };
using var collection = new CosmosMongoCollection<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 => CosmosMongoTestStore.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 CosmosMongoDB.ConformanceTests.Support;
using VectorData.ConformanceTests;
using Xunit;
namespace CosmosMongoDB.ConformanceTests;
public class CosmosMongoCollectionManagementTests(CosmosMongoFixture fixture)
: CollectionManagementTests<string>(fixture), IClassFixture<CosmosMongoFixture>
{
}
@@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net10.0;net472</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsTestProject>true</IsTestProject>
<IsPackable>false</IsPackable>
<RootNamespace>CosmosMongoDB.ConformanceTests</RootNamespace>
<UserSecretsId>b7762d10-e29b-4bb1-8b74-b6d69a667dd4</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\VectorData\CosmosMongoDB\CosmosMongoDB.csproj" />
<ProjectReference Include="..\VectorData.ConformanceTests\VectorData.ConformanceTests.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="testsettings.json" Condition="Exists('testsettings.json')">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="testsettings.development.json" Condition="Exists('testsettings.development.json')">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,142 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel.Connectors.CosmosMongoDB;
using MongoDB.Driver;
using VectorData.ConformanceTests;
using Xunit;
namespace CosmosMongoDB.ConformanceTests;
public class CosmosMongoDependencyInjectionTests
: DependencyInjectionTests<CosmosMongoVectorStore, CosmosMongoCollection<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("CosmosMongo", serviceKey, "ConnectionString"), ConnectionString),
new(CreateConfigKey("CosmosMongo", serviceKey, "DatabaseName"), DatabaseName),
]);
private static string ConnectionStringProvider(IServiceProvider sp)
=> sp.GetRequiredService<IConfiguration>().GetRequiredSection("CosmosMongo:ConnectionString").Value!;
private static string ConnectionStringProvider(IServiceProvider sp, object serviceKey)
=> sp.GetRequiredService<IConfiguration>().GetRequiredSection(CreateConfigKey("CosmosMongo", serviceKey, "ConnectionString")).Value!;
private static string DatabaseNameProvider(IServiceProvider sp)
=> sp.GetRequiredService<IConfiguration>().GetRequiredSection("CosmosMongo:DatabaseName").Value!;
private static string DatabaseNameProvider(IServiceProvider sp, object serviceKey)
=> sp.GetRequiredService<IConfiguration>().GetRequiredSection(CreateConfigKey("CosmosMongo", 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))
.AddCosmosMongoCollection<Record>(name, lifetime: lifetime)
: services
.AddSingleton<MongoClient>(sp => new MongoClient(MongoClientSettings.FromConnectionString(ConnectionString)))
.AddSingleton<IMongoDatabase>(sp => sp.GetRequiredService<MongoClient>().GetDatabase(DatabaseName))
.AddKeyedCosmosMongoCollection<Record>(serviceKey, name, lifetime: lifetime);
yield return (services, serviceKey, name, lifetime) => serviceKey is null
? services.AddCosmosMongoCollection<Record>(
name, ConnectionString, DatabaseName, lifetime: lifetime)
: services.AddKeyedCosmosMongoCollection<Record>(
serviceKey, name, ConnectionString, DatabaseName, lifetime: lifetime);
yield return (services, serviceKey, name, lifetime) => serviceKey is null
? services.AddCosmosMongoCollection<Record>(
name, ConnectionStringProvider, DatabaseNameProvider, lifetime: lifetime)
: services.AddKeyedCosmosMongoCollection<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.AddCosmosMongoVectorStore(
ConnectionString, DatabaseName, lifetime: lifetime)
: services.AddKeyedCosmosMongoVectorStore(
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))
.AddCosmosMongoVectorStore(lifetime: lifetime)
: services
.AddSingleton<MongoClient>(sp => new MongoClient(MongoClientSettings.FromConnectionString(ConnectionString)))
.AddSingleton<IMongoDatabase>(sp => sp.GetRequiredService<MongoClient>().GetDatabase(DatabaseName))
.AddKeyedCosmosMongoVectorStore(serviceKey, lifetime: lifetime);
}
}
[Fact]
public void ConnectionStringProviderCantBeNull()
{
IServiceCollection services = new ServiceCollection();
Assert.Throws<ArgumentNullException>(() => services.AddCosmosMongoCollection<Record>(
name: "notNull", connectionStringProvider: null!, databaseNameProvider: DatabaseNameProvider));
Assert.Throws<ArgumentNullException>(() => services.AddKeyedCosmosMongoCollection<Record>(
serviceKey: "notNull", name: "notNull", connectionStringProvider: null!, databaseNameProvider: DatabaseNameProvider));
}
[Fact]
public void DatabaseNameProviderCantBeNull()
{
IServiceCollection services = new ServiceCollection();
Assert.Throws<ArgumentNullException>(() => services.AddCosmosMongoCollection<Record>(
name: "notNull", connectionStringProvider: ConnectionStringProvider, databaseNameProvider: null!));
Assert.Throws<ArgumentNullException>(() => services.AddKeyedCosmosMongoCollection<Record>(
serviceKey: "notNull", name: "notNull", connectionStringProvider: ConnectionStringProvider, databaseNameProvider: null!));
}
[Fact]
public void ConnectionStringCantBeNullOrEmpty()
{
IServiceCollection services = new ServiceCollection();
Assert.Throws<ArgumentNullException>(() => services.AddCosmosMongoVectorStore(connectionString: null!, DatabaseName));
Assert.Throws<ArgumentNullException>(() => services.AddKeyedCosmosMongoVectorStore(serviceKey: "notNull", connectionString: null!, DatabaseName));
Assert.Throws<ArgumentNullException>(() => services.AddCosmosMongoCollection<Record>(
name: "notNull", connectionString: null!, DatabaseName));
Assert.Throws<ArgumentException>(() => services.AddCosmosMongoCollection<Record>(
name: "notNull", connectionString: "", DatabaseName));
Assert.Throws<ArgumentNullException>(() => services.AddKeyedCosmosMongoCollection<Record>(
serviceKey: "notNull", name: "notNull", connectionString: null!, DatabaseName));
Assert.Throws<ArgumentException>(() => services.AddKeyedCosmosMongoCollection<Record>(
serviceKey: "notNull", name: "notNull", connectionString: "", DatabaseName));
}
[Fact]
public void DatabaseNameCantBeNullOrEmpty()
{
IServiceCollection services = new ServiceCollection();
Assert.Throws<ArgumentNullException>(() => services.AddCosmosMongoVectorStore(ConnectionString, databaseName: null!));
Assert.Throws<ArgumentNullException>(() => services.AddKeyedCosmosMongoVectorStore(serviceKey: "notNull", ConnectionString, databaseName: null!));
Assert.Throws<ArgumentNullException>(() => services.AddCosmosMongoCollection<Record>(
name: "notNull", ConnectionString, databaseName: null!));
Assert.Throws<ArgumentException>(() => services.AddCosmosMongoCollection<Record>(
name: "notNull", ConnectionString, databaseName: ""));
Assert.Throws<ArgumentNullException>(() => services.AddKeyedCosmosMongoCollection<Record>(
serviceKey: "notNull", name: "notNull", ConnectionString, databaseName: null!));
Assert.Throws<ArgumentException>(() => services.AddKeyedCosmosMongoCollection<Record>(
serviceKey: "notNull", name: "notNull", ConnectionString, databaseName: ""));
}
}
@@ -0,0 +1,25 @@
// Copyright (c) Microsoft. All rights reserved.
using CosmosMongoDB.ConformanceTests.Support;
using VectorData.ConformanceTests;
using VectorData.ConformanceTests.Support;
using Xunit;
namespace CosmosMongoDB.ConformanceTests;
public class CosmosMongoDistanceFunctionTests(CosmosMongoDistanceFunctionTests.Fixture fixture)
: DistanceFunctionTests<int>(fixture), IClassFixture<CosmosMongoDistanceFunctionTests.Fixture>
{
public override Task CosineSimilarity() => Assert.ThrowsAsync<NotSupportedException>(base.CosineSimilarity);
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 => CosmosMongoTestStore.Instance;
public override bool AssertScores { get; } = false;
}
}
@@ -0,0 +1,59 @@
// Copyright (c) Microsoft. All rights reserved.
using CosmosMongoDB.ConformanceTests.Support;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.VectorData;
using VectorData.ConformanceTests;
using VectorData.ConformanceTests.Support;
using Xunit;
namespace CosmosMongoDB.ConformanceTests;
public class CosmosMongoEmbeddingGenerationTests(CosmosMongoEmbeddingGenerationTests.StringVectorFixture stringVectorFixture, CosmosMongoEmbeddingGenerationTests.RomOfFloatVectorFixture romOfFloatVectorFixture)
: EmbeddingGenerationTests<string>(stringVectorFixture, romOfFloatVectorFixture), IClassFixture<CosmosMongoEmbeddingGenerationTests.StringVectorFixture>, IClassFixture<CosmosMongoEmbeddingGenerationTests.RomOfFloatVectorFixture>
{
public new class StringVectorFixture : EmbeddingGenerationTests<string>.StringVectorFixture
{
public override TestStore TestStore => CosmosMongoTestStore.Instance;
public override VectorStore CreateVectorStore(IEmbeddingGenerator? embeddingGenerator)
=> CosmosMongoTestStore.Instance.GetVectorStore(new() { EmbeddingGenerator = embeddingGenerator });
public override Func<IServiceCollection, IServiceCollection>[] DependencyInjectionStoreRegistrationDelegates =>
[
services => services
.AddSingleton(CosmosMongoTestStore.Instance.Database)
.AddCosmosMongoVectorStore()
];
public override Func<IServiceCollection, IServiceCollection>[] DependencyInjectionCollectionRegistrationDelegates =>
[
services => services
.AddSingleton(CosmosMongoTestStore.Instance.Database)
.AddCosmosMongoCollection<RecordWithAttributes>(this.CollectionName)
];
}
public new class RomOfFloatVectorFixture : EmbeddingGenerationTests<string>.RomOfFloatVectorFixture
{
public override TestStore TestStore => CosmosMongoTestStore.Instance;
public override VectorStore CreateVectorStore(IEmbeddingGenerator? embeddingGenerator)
=> CosmosMongoTestStore.Instance.GetVectorStore(new() { EmbeddingGenerator = embeddingGenerator });
public override Func<IServiceCollection, IServiceCollection>[] DependencyInjectionStoreRegistrationDelegates =>
[
services => services
.AddSingleton(CosmosMongoTestStore.Instance.Database)
.AddCosmosMongoVectorStore()
];
public override Func<IServiceCollection, IServiceCollection>[] DependencyInjectionCollectionRegistrationDelegates =>
[
services => services
.AddSingleton(CosmosMongoTestStore.Instance.Database)
.AddCosmosMongoCollection<RecordWithAttributes>(this.CollectionName)
];
}
}
@@ -0,0 +1,66 @@
// Copyright (c) Microsoft. All rights reserved.
using CosmosMongoDB.ConformanceTests.Support;
using VectorData.ConformanceTests;
using VectorData.ConformanceTests.Support;
using VectorData.ConformanceTests.Xunit;
using Xunit;
namespace CosmosMongoDB.ConformanceTests;
public class CosmosMongoFilterTests(CosmosMongoFilterTests.Fixture fixture)
: FilterTests<string>(fixture), IClassFixture<CosmosMongoFilterTests.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 new class Fixture : FilterTests<string>.Fixture
{
public override TestStore TestStore => CosmosMongoTestStore.Instance;
protected override string IndexKind => Microsoft.Extensions.VectorData.IndexKind.IvfFlat;
protected override string DistanceFunction => Microsoft.Extensions.VectorData.DistanceFunction.CosineDistance;
}
}
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft. All rights reserved.
using CosmosMongoDB.ConformanceTests.Support;
using Microsoft.Extensions.VectorData;
using VectorData.ConformanceTests;
using VectorData.ConformanceTests.Support;
using VectorData.ConformanceTests.Xunit;
using Xunit;
namespace CosmosMongoDB.ConformanceTests;
public class CosmosMongoIndexKindTests(CosmosMongoIndexKindTests.Fixture fixture)
: IndexKindTests<int>(fixture), IClassFixture<CosmosMongoIndexKindTests.Fixture>
{
// Note: Cosmos Mongo support HNSW, but only in a specific tier.
// [ConditionalFact]
// public virtual Task Hnsw()
// => this.Test(IndexKind.Hnsw);
[ConditionalFact]
public virtual Task IvfFlat()
=> this.Test(IndexKind.IvfFlat);
// Cosmos Mongo does not support index-less searching
public override Task Flat() => Assert.ThrowsAsync<NotSupportedException>(base.Flat);
public new class Fixture() : IndexKindTests<int>.Fixture
{
public override TestStore TestStore => CosmosMongoTestStore.Instance;
}
}
@@ -0,0 +1,17 @@
// Copyright (c) Microsoft. All rights reserved.
using VectorData.ConformanceTests;
using VectorData.ConformanceTests.ModelTests;
namespace CosmosMongoDB.ConformanceTests;
public class CosmosMongoTestSuiteImplementationTests : TestSuiteImplementationTests
{
protected override ICollection<Type> IgnoredTestBases { get; } =
[
typeof(DynamicModelTests<>),
// Hybrid search not supported
typeof(HybridSearchTests<>),
];
}
@@ -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<string>(fixture), IClassFixture<CosmosMongoBasicModelTests.Fixture>
{
public new class Fixture : BasicModelTests<string>.Fixture
{
public override TestStore TestStore => CosmosMongoTestStore.Instance;
}
}
@@ -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 CosmosMongoMultiVectorModelTests(CosmosMongoMultiVectorModelTests.Fixture fixture)
: MultiVectorModelTests<string>(fixture), IClassFixture<CosmosMongoMultiVectorModelTests.Fixture>
{
public new class Fixture : MultiVectorModelTests<string>.Fixture
{
public override TestStore TestStore => CosmosMongoTestStore.Instance;
}
}
@@ -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<string>(fixture), IClassFixture<CosmosMongoNoDataModelTests.Fixture>
{
public new class Fixture : NoDataModelTests<string>.Fixture
{
public override TestStore TestStore => CosmosMongoTestStore.Instance;
}
}
@@ -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<string>(fixture), IClassFixture<CosmosMongoNoVectorModelTests.Fixture>
{
public new class Fixture : NoVectorModelTests<string>.Fixture
{
public override TestStore TestStore => CosmosMongoTestStore.Instance;
}
}
@@ -0,0 +1,3 @@
// Copyright (c) Microsoft. All rights reserved.
[assembly: CosmosMongoDB.ConformanceTests.Support.CosmosConnectionStringRequired]
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft. All rights reserved.
using VectorData.ConformanceTests.Xunit;
namespace CosmosMongoDB.ConformanceTests.Support;
/// <summary>
/// Checks whether the sqlite_vec extension is properly installed, and skips the test(s) otherwise.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)]
public sealed class CosmosConnectionStringRequiredAttribute : Attribute, ITestCondition
{
public ValueTask<bool> IsMetAsync() => new(CosmosMongoTestEnvironment.IsConnectionStringDefined);
public string Skip { get; set; } = "The Cosmos connection string hasn't been configured (CosmosMongo:ConnectionString).";
public string SkipReason
=> this.Skip;
}
@@ -0,0 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.
using VectorData.ConformanceTests.Support;
namespace CosmosMongoDB.ConformanceTests.Support;
public class CosmosMongoFixture : VectorStoreFixture
{
public override TestStore TestStore => CosmosMongoTestStore.Instance;
}
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Extensions.Configuration;
namespace CosmosMongoDB.ConformanceTests.Support;
#pragma warning disable CA1810 // Initialize all static fields when those fields are declared
public static class CosmosMongoTestEnvironment
{
public static readonly string? ConnectionString;
public static bool IsConnectionStringDefined => ConnectionString is not null;
static CosmosMongoTestEnvironment()
{
var configuration = new ConfigurationBuilder()
.AddJsonFile(path: "testsettings.json", optional: true)
.AddJsonFile(path: "testsettings.development.json", optional: true)
.AddEnvironmentVariables()
.AddUserSecrets<CosmosConnectionStringRequiredAttribute>()
.Build();
ConnectionString = configuration["CosmosMongo:ConnectionString"];
}
}
@@ -0,0 +1,45 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.SemanticKernel.Connectors.CosmosMongoDB;
using MongoDB.Driver;
using VectorData.ConformanceTests.Support;
namespace CosmosMongoDB.ConformanceTests.Support;
#pragma warning disable CA1001
public sealed class CosmosMongoTestStore : TestStore
#pragma warning restore CA1001
{
public static CosmosMongoTestStore Instance { get; } = new();
private MongoClient? _client;
private IMongoDatabase? _database;
public MongoClient Client => this._client ?? throw new InvalidOperationException("Not initialized");
public IMongoDatabase Database => this._database ?? throw new InvalidOperationException("Not initialized");
public override string DefaultIndexKind => Microsoft.Extensions.VectorData.IndexKind.IvfFlat;
public override string DefaultDistanceFunction => Microsoft.Extensions.VectorData.DistanceFunction.CosineDistance;
public CosmosMongoVectorStore GetVectorStore(CosmosMongoVectorStoreOptions options)
=> new(this.Database, options);
private CosmosMongoTestStore()
{
}
protected override Task StartAsync()
{
if (string.IsNullOrWhiteSpace(CosmosMongoTestEnvironment.ConnectionString))
{
throw new InvalidOperationException("Connection string is not configured, set the CosmosMongo:ConnectionString environment variable");
}
this._client = new MongoClient(CosmosMongoTestEnvironment.ConnectionString);
this._database = this._client.GetDatabase("VectorSearchTests");
this.DefaultVectorStore = new CosmosMongoVectorStore(this._database);
return Task.CompletedTask;
}
}
@@ -0,0 +1,50 @@
// Copyright (c) Microsoft. All rights reserved.
using CosmosMongoDB.ConformanceTests.Support;
using VectorData.ConformanceTests.Support;
using VectorData.ConformanceTests.TypeTests;
using Xunit;
namespace CosmosMongoDB.ConformanceTests.TypeTests;
public class CosmosMongoDataTypeTests(CosmosMongoDataTypeTests.Fixture fixture)
: DataTypeTests<string, DataTypeTests<string>.DefaultRecord>(fixture), IClassFixture<CosmosMongoDataTypeTests.Fixture>
{
public override Task Decimal()
=> this.Test<decimal>(
"Decimal", 8.5m, 9.5m,
isFilterable: false); // TODO: Filtering doesn't fail but the data doesn't seem to appear...
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, DateTimeKind.Utc));
// 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));
public new class Fixture : DataTypeTests<string, DataTypeTests<string>.DefaultRecord>.Fixture
{
public override TestStore TestStore => CosmosMongoTestStore.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 CosmosMongoDB.ConformanceTests.Support;
using VectorData.ConformanceTests.Support;
using VectorData.ConformanceTests.TypeTests;
using Xunit;
#pragma warning disable CA2000 // Dispose objects before losing scope
namespace CosmosMongoDB.ConformanceTests.TypeTests;
public class CosmosMongoEmbeddingTypeTests(CosmosMongoEmbeddingTypeTests.Fixture fixture)
: EmbeddingTypeTests<string>(fixture), IClassFixture<CosmosMongoEmbeddingTypeTests.Fixture>
{
public new class Fixture : EmbeddingTypeTests<string>.Fixture
{
public override TestStore TestStore => CosmosMongoTestStore.Instance;
}
}
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft. All rights reserved.
using CosmosMongoDB.ConformanceTests.Support;
using MongoDB.Bson;
using VectorData.ConformanceTests.Support;
using VectorData.ConformanceTests.TypeTests;
using VectorData.ConformanceTests.Xunit;
using Xunit;
namespace CosmosMongoDB.ConformanceTests.TypeTests;
public class CosmosMongoKeyTypeTests(CosmosMongoKeyTypeTests.Fixture fixture)
: KeyTypeTests(fixture), IClassFixture<CosmosMongoKeyTypeTests.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 => CosmosMongoTestStore.Instance;
}
}