// Copyright (c) Microsoft. All rights reserved. using Microsoft.Extensions.VectorData; using VectorData.ConformanceTests.Support; using VectorData.ConformanceTests.Xunit; using Xunit; namespace VectorData.ConformanceTests; public abstract class CollectionManagementTests(VectorStoreFixture fixture) : IAsyncLifetime where TKey : notnull { public Task InitializeAsync() => fixture.VectorStore.EnsureCollectionDeletedAsync(this.CollectionName); [ConditionalFact] public async Task Collection_Ensure_Exists_Delete() { var collection = this.GetCollection(); Assert.False(await collection.CollectionExistsAsync()); await collection.EnsureCollectionExistsAsync(); Assert.True(await collection.CollectionExistsAsync()); await collection.EnsureCollectionDeletedAsync(); Assert.False(await collection.CollectionExistsAsync()); // Deleting a non-existing collection does not throw await fixture.TestStore.DefaultVectorStore.EnsureCollectionDeletedAsync(collection.Name); } [ConditionalFact] public async Task EnsureCollectionExists_twice_does_not_throw() { var collection = this.GetCollection(); await collection.EnsureCollectionExistsAsync(); await collection.EnsureCollectionExistsAsync(); Assert.True(await collection.CollectionExistsAsync()); } [ConditionalFact] public async Task Store_CollectionExists() { var store = fixture.VectorStore; var collection = this.GetCollection(); Assert.False(await store.CollectionExistsAsync(collection.Name)); await collection.EnsureCollectionExistsAsync(); Assert.True(await store.CollectionExistsAsync(collection.Name)); } [ConditionalFact] public async Task Store_DeleteCollection() { var store = fixture.VectorStore; var collection = this.GetCollection(); await collection.EnsureCollectionExistsAsync(); await fixture.TestStore.DefaultVectorStore.EnsureCollectionDeletedAsync(collection.Name); Assert.False(await collection.CollectionExistsAsync()); } [ConditionalFact] public async Task Store_ListCollections() { var store = fixture.VectorStore; var collection = this.GetCollection(); Assert.Empty(await store.ListCollectionNamesAsync().Where(n => n == collection.Name).ToListAsync()); await collection.EnsureCollectionExistsAsync(); var name = Assert.Single(await store.ListCollectionNamesAsync().Where(n => n == collection.Name).ToListAsync()); Assert.Equal(collection.Name, name); } [ConditionalFact] public void Collection_metadata() { var collection = this.GetCollection(); var collectionMetadata = (VectorStoreCollectionMetadata?)collection.GetService(typeof(VectorStoreCollectionMetadata)); Assert.NotNull(collectionMetadata); Assert.NotNull(collectionMetadata.VectorStoreSystemName); Assert.NotNull(collectionMetadata.CollectionName); } protected virtual string CollectionNameBase => nameof(CollectionManagementTests); public virtual string CollectionName => fixture.TestStore.AdjustCollectionName(this.CollectionNameBase); public sealed class Record : TestRecord { public string? Text { get; set; } public int Number { get; set; } public ReadOnlyMemory Floats { get; set; } } public virtual VectorStoreCollection GetCollection() => fixture.TestStore.CreateCollection(this.CollectionName, this.CreateRecordDefinition()); public virtual VectorStoreCollectionDefinition CreateRecordDefinition() => new() { Properties = [ new VectorStoreKeyProperty(nameof(Record.Key), typeof(TKey)) { StorageName = "key" }, new VectorStoreDataProperty(nameof(Record.Text), typeof(string)) { StorageName = "text" }, new VectorStoreDataProperty(nameof(Record.Number), typeof(int)) { StorageName = "number" }, new VectorStoreVectorProperty(nameof(Record.Floats), typeof(ReadOnlyMemory), 10) { IndexKind = fixture.TestStore.DefaultIndexKind } ] }; public Task DisposeAsync() => Task.CompletedTask; }