Skip to main content
Glama

Azure MCP Server

Official
MIT License
1,161
  • Linux
  • Apple
StorageCommandTests.cs26.4 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Text.Json; using AzureMcp.Tests; using AzureMcp.Tests.Client; using AzureMcp.Tests.Client.Helpers; using Xunit; namespace AzureMcp.Storage.LiveTests { public class StorageCommandTests(LiveTestFixture liveTestFixture, ITestOutputHelper output) : CommandTestsBase(liveTestFixture, output), IClassFixture<LiveTestFixture> { [Fact] public async Task Should_list_storage_accounts_by_subscription_id() { var result = await CallToolAsync( "azmcp_storage_account_list", new() { { "subscription", Settings.SubscriptionId } }); var accounts = result.AssertProperty("accounts"); Assert.Equal(JsonValueKind.Array, accounts.ValueKind); Assert.NotEmpty(accounts.EnumerateArray()); } [Fact] public async Task Should_get_storage_account_details_by_subscription_id() { var result = await CallToolAsync( "azmcp_storage_account_details", new() { { "subscription", Settings.SubscriptionId }, { "account", Settings.ResourceBaseName } }); var account = result.AssertProperty("account"); Assert.Equal(JsonValueKind.Object, account.ValueKind); // Verify the account has basic properties var name = account.GetProperty("name"); Assert.Equal(Settings.ResourceBaseName, name.GetString()); var location = account.GetProperty("location"); Assert.NotNull(location.GetString()); var kind = account.GetProperty("kind"); Assert.Equal("StorageV2", kind.GetString()); var skuName = account.GetProperty("skuName"); Assert.Equal("Standard_LRS", skuName.GetString()); var hnsEnabled = account.GetProperty("hnsEnabled"); Assert.True(hnsEnabled.GetBoolean()); } [Fact] public async Task Should_get_storage_account_details_by_subscription_name() { var result = await CallToolAsync( "azmcp_storage_account_details", new() { { "subscription", Settings.SubscriptionName }, { "account", Settings.ResourceBaseName } }); var account = result.AssertProperty("account"); Assert.Equal(JsonValueKind.Object, account.ValueKind); var name = account.GetProperty("name"); Assert.Equal(Settings.ResourceBaseName, name.GetString()); var kind = account.GetProperty("kind"); Assert.Equal("StorageV2", kind.GetString()); } [Fact] public async Task Should_get_storage_account_details_with_tenant_id() { var result = await CallToolAsync( "azmcp_storage_account_details", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantId }, { "account", Settings.ResourceBaseName } }); var account = result.AssertProperty("account"); Assert.Equal(JsonValueKind.Object, account.ValueKind); var name = account.GetProperty("name"); Assert.Equal(Settings.ResourceBaseName, name.GetString()); } [Fact()] public async Task Should_get_storage_account_details_with_tenant_name() { Assert.SkipWhen(Settings.IsServicePrincipal, TenantNameReason); var result = await CallToolAsync( "azmcp_storage_account_details", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantName }, { "account", Settings.ResourceBaseName } }); var account = result.AssertProperty("account"); Assert.Equal(JsonValueKind.Object, account.ValueKind); var name = account.GetProperty("name"); Assert.Equal(Settings.ResourceBaseName, name.GetString()); } [Fact] public async Task Should_list_storage_accounts_by_subscription_name() { var result = await CallToolAsync( "azmcp_storage_account_list", new() { { "subscription", Settings.SubscriptionName } }); var accounts = result.AssertProperty("accounts"); Assert.Equal(JsonValueKind.Array, accounts.ValueKind); Assert.NotEmpty(accounts.EnumerateArray()); } [Fact] public async Task Should_list_storage_accounts_by_subscription_name_with_tenant_id() { var result = await CallToolAsync( "azmcp_storage_account_list", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantId } }); var accounts = result.AssertProperty("accounts"); Assert.Equal(JsonValueKind.Array, accounts.ValueKind); Assert.NotEmpty(accounts.EnumerateArray()); } [Fact()] public async Task Should_list_storage_accounts_by_subscription_name_with_tenant_name() { Assert.SkipWhen(Settings.IsServicePrincipal, TenantNameReason); var result = await CallToolAsync( "azmcp_storage_account_list", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantName } }); var accounts = result.AssertProperty("accounts"); Assert.Equal(JsonValueKind.Array, accounts.ValueKind); Assert.NotEmpty(accounts.EnumerateArray()); } [Fact] public async Task Should_list_blobs_in_container() { var result = await CallToolAsync( "azmcp_storage_blob_list", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantId }, { "account", Settings.ResourceBaseName }, { "container", "bar" }, }); var actual = result.AssertProperty("blobs"); Assert.Equal(JsonValueKind.Array, actual.ValueKind); Assert.NotEmpty(actual.EnumerateArray()); } [Fact] public async Task Should_get_blob_details() { var result = await CallToolAsync( "azmcp_storage_blob_details", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantId }, { "account", Settings.ResourceBaseName }, { "container", "bar" }, { "blob", "README.md" }, }); var details = result.AssertProperty("details"); Assert.Equal(JsonValueKind.Object, details.ValueKind); // Verify the blob has basic properties var contentLength = details.GetProperty("contentLength"); Assert.True(contentLength.GetInt64() > 0); var contentType = details.GetProperty("contentType"); Assert.NotNull(contentType.GetString()); var lastModified = details.GetProperty("lastModified"); Assert.NotEqual(default, lastModified.GetDateTimeOffset()); } [Fact] public async Task Should_upload_blob() { // Create a temporary file to upload var tempFileName = $"test-upload-{DateTime.UtcNow.Ticks}.txt"; var tempFilePath = Path.Combine(Path.GetTempPath(), tempFileName); var testContent = "This is a test file for blob upload"; try { await File.WriteAllTextAsync(tempFilePath, testContent, TestContext.Current.CancellationToken); var result = await CallToolAsync( "azmcp_storage_blob_upload", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantId }, { "account", Settings.ResourceBaseName }, { "container", "bar" }, { "blob", tempFileName }, { "local-file-path", tempFilePath } }); // Verify upload details var blobName = result.AssertProperty("blob"); Assert.Equal(tempFileName, blobName.GetString()); var containerName = result.AssertProperty("container"); Assert.Equal("bar", containerName.GetString()); var uploadedFile = result.AssertProperty("uploadedFile"); Assert.Equal(tempFilePath, uploadedFile.GetString()); var eTag = result.AssertProperty("eTag"); Assert.NotNull(eTag.GetString()); Assert.NotEmpty(eTag.GetString()!); } finally { // Clean up the temporary file if (File.Exists(tempFilePath)) { File.Delete(tempFilePath); } } } [Fact] public async Task Should_upload_blob_with_overwrite() { // Create a temporary file to upload var tempFileName = $"test-overwrite-{DateTime.UtcNow.Ticks}.txt"; var tempFilePath = Path.Combine(Path.GetTempPath(), tempFileName); var testContent = "This is a test file for blob overwrite"; try { await File.WriteAllTextAsync(tempFilePath, testContent, TestContext.Current.CancellationToken); // First upload await CallToolAsync( "azmcp_storage_blob_upload", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantId }, { "account", Settings.ResourceBaseName }, { "container", "bar" }, { "blob", tempFileName }, { "local-file-path", tempFilePath } }); // Second upload with overwrite var result = await CallToolAsync( "azmcp_storage_blob_upload", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantId }, { "account", Settings.ResourceBaseName }, { "container", "bar" }, { "blob", tempFileName }, { "local-file-path", tempFilePath }, { "overwrite", true } }); // Verify upload details var blobName = result.AssertProperty("blob"); Assert.Equal(tempFileName, blobName.GetString()); var containerName = result.AssertProperty("container"); Assert.Equal("bar", containerName.GetString()); var uploadedFile = result.AssertProperty("uploadedFile"); Assert.Equal(tempFilePath, uploadedFile.GetString()); var eTag = result.AssertProperty("eTag"); Assert.NotNull(eTag.GetString()); Assert.NotEmpty(eTag.GetString()!); } finally { // Clean up the temporary file if (File.Exists(tempFilePath)) { File.Delete(tempFilePath); } } } [Fact] public async Task Should_list_containers() { var result = await CallToolAsync( "azmcp_storage_blob_container_list", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantId }, { "account", Settings.ResourceBaseName }, { "retry-max-retries", 0 } }); var actual = result.AssertProperty("containers"); Assert.Equal(JsonValueKind.Array, actual.ValueKind); Assert.NotEmpty(actual.EnumerateArray()); } [Fact] public async Task Should_list_storage_tables() { var result = await CallToolAsync( "azmcp_storage_table_list", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantId }, { "account", Settings.ResourceBaseName }, }); var actual = result.AssertProperty("tables"); Assert.Equal(JsonValueKind.Array, actual.ValueKind); Assert.NotEmpty(actual.EnumerateArray()); } [Fact] public async Task Should_list_storage_tables_with_tenant_id() { var result = await CallToolAsync( "azmcp_storage_table_list", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantId }, { "account", Settings.ResourceBaseName }, }); var actual = result.AssertProperty("tables"); Assert.Equal(JsonValueKind.Array, actual.ValueKind); Assert.NotEmpty(actual.EnumerateArray()); } [Fact()] public async Task Should_list_storage_tables_with_tenant_name() { Assert.SkipWhen(Settings.IsServicePrincipal, TenantNameReason); var result = await CallToolAsync( "azmcp_storage_table_list", new() { { "subscription", Settings.SubscriptionName }, { "tenant", Settings.TenantName }, { "account", Settings.ResourceBaseName }, }); var actual = result.AssertProperty("tables"); Assert.Equal(JsonValueKind.Array, actual.ValueKind); Assert.NotEmpty(actual.EnumerateArray()); } [Fact] public async Task Should_get_container_details() { var result = await CallToolAsync( "azmcp_storage_blob_container_details", new() { { "subscription", Settings.SubscriptionName }, { "account", Settings.ResourceBaseName }, { "container", "bar" } }); var actual = result.AssertProperty("details"); Assert.Equal(JsonValueKind.Object, actual.ValueKind); } [Fact] public async Task Should_get_container_details_with_tenant_authkey() { var result = await CallToolAsync( "azmcp_storage_blob_container_details", new() { { "subscription", Settings.SubscriptionName }, { "account", Settings.ResourceBaseName }, { "container", "bar" }, { "auth-method", "key" } }); var actual = result.AssertProperty("details"); Assert.Equal(JsonValueKind.Object, actual.ValueKind); } [Fact] public async Task Should_create_container() { var containerName = $"test-container-{DateTime.UtcNow.Ticks}"; var result = await CallToolAsync( "azmcp_storage_blob_container_create", new() { { "subscription", Settings.SubscriptionName }, { "account", Settings.ResourceBaseName }, { "container", containerName } }); var actual = result.AssertProperty("container"); Assert.Equal(JsonValueKind.Object, actual.ValueKind); Assert.True(actual.TryGetProperty("lastModified", out _)); Assert.True(actual.TryGetProperty("eTag", out _)); Assert.True(actual.TryGetProperty("publicAccess", out _)); } [Fact] public async Task Should_list_datalake_filesystem_paths() { var result = await CallToolAsync( "azmcp_storage_datalake_file-system_list-paths", new() { { "subscription", Settings.SubscriptionName }, { "account", Settings.ResourceBaseName }, { "file-system", "testfilesystem" } }); var actual = result.AssertProperty("paths"); Assert.Equal(JsonValueKind.Array, actual.ValueKind); } [Fact] public async Task Should_list_datalake_filesystem_paths_recursively() { var result = await CallToolAsync( "azmcp_storage_datalake_file-system_list-paths", new() { { "subscription", Settings.SubscriptionName }, { "account", Settings.ResourceBaseName }, { "file-system", "testfilesystem" }, { "recursive", true } }); var actual = result.AssertProperty("paths"); Assert.Equal(JsonValueKind.Array, actual.ValueKind); } [Fact] public async Task Should_create_datalake_directory() { var directoryPath = "testfilesystem/test-directory"; var result = await CallToolAsync( "azmcp_storage_datalake_directory_create", new() { { "subscription", Settings.SubscriptionName }, { "account", Settings.ResourceBaseName }, { "directory-path", directoryPath } }); var directory = result.AssertProperty("directory"); Assert.Equal(JsonValueKind.Object, directory.ValueKind); var name = directory.GetProperty("name").GetString(); var type = directory.GetProperty("type").GetString(); Assert.Equal(directoryPath, name); Assert.Equal("directory", type); } [Fact] public async Task Should_set_blob_tier_batch() { // This test assumes the test storage account has the "bar" container with some test blobs // We'll set tier to Cool for multiple blobs var result = await CallToolAsync( "azmcp_storage_blob_batch_set-tier", new() { { "subscription", Settings.SubscriptionName }, { "account", Settings.ResourceBaseName }, { "container", "bar" }, { "tier", "Cool" }, { "blobs", "blob1.txt blob2.txt" } }); var successfulBlobs = result.AssertProperty("successfulBlobs"); var failedBlobs = result.AssertProperty("failedBlobs"); Assert.Equal(JsonValueKind.Array, successfulBlobs.ValueKind); Assert.Equal(JsonValueKind.Array, failedBlobs.ValueKind); // At least one of the blobs should succeed if they exist, or all should be in failed if they don't exist var successCount = successfulBlobs.GetArrayLength(); var failedCount = failedBlobs.GetArrayLength(); Assert.True(successCount + failedCount > 0, "Should have processed at least one blob"); } [Fact] public async Task Should_list_files_in_share_directory() { var result = await CallToolAsync( "azmcp_storage_share_file_list", new() { { "subscription", Settings.SubscriptionName }, { "account", Settings.ResourceBaseName }, { "share", "testshare" }, { "directory-path", "/" } }); var files = result.AssertProperty("files"); Assert.Equal(JsonValueKind.Array, files.ValueKind); Assert.NotEmpty(files.EnumerateArray()); } [Fact] public async Task Should_list_files_in_share_directory_with_prefix() { var result = await CallToolAsync( "azmcp_storage_share_file_list", new() { { "subscription", Settings.SubscriptionName }, { "account", Settings.ResourceBaseName }, { "share", "testshare" }, { "directory-path", "/" }, { "prefix", "NoSuchPrefix" } }); // When using a prefix that does not match any files, we should still return a valid response // with no result. Assert.Null(result); } [Fact] public async Task Should_SendQueueMessage_Successfully() { // Arrange var result = await CallToolAsync( "azmcp_storage_queue_message_send", new() { { "subscription", Settings.SubscriptionId }, { "account", Settings.ResourceBaseName }, { "queue", "testqueue" }, { "message", "Test message from integration test" } }); // Assert var message = result.AssertProperty("message"); Assert.Equal(JsonValueKind.Object, message.ValueKind); // Check message properties Assert.True(message.TryGetProperty("messageId", out _)); Assert.True(message.TryGetProperty("insertionTime", out _)); Assert.True(message.TryGetProperty("expirationTime", out _)); Assert.True(message.TryGetProperty("popReceipt", out _)); Assert.True(message.TryGetProperty("nextVisibleTime", out _)); Assert.True(message.TryGetProperty("message", out var messageElement)); Assert.Equal("Test message from integration test", messageElement.GetString()); } [Fact] public async Task Should_SendQueueMessage_WithOptionalParameters() { // Arrange var result = await CallToolAsync( "azmcp_storage_queue_message_send", new() { { "subscription", Settings.SubscriptionId }, { "account", Settings.ResourceBaseName }, { "queue", "testqueue" }, { "message", "Test message with TTL" }, { "time-to-live-in-seconds", "3600" }, { "visibility-timeout-in-seconds", "30" } }); // Assert var message = result.AssertProperty("message"); Assert.Equal(JsonValueKind.Object, message.ValueKind); Assert.True(message.TryGetProperty("message", out var messageElement)); Assert.Equal("Test message with TTL", messageElement.GetString()); } [Fact] public async Task Should_CreateStorageAccount_Successfully() { // Arrange - Use a unique account name for testing var uniqueAccountName = $"testacct{DateTime.UtcNow:MMddHHmmss}"; var result = await CallToolAsync( "azmcp_storage_account_create", new() { { "subscription", Settings.SubscriptionId }, { "account", uniqueAccountName }, { "resource-group", Settings.ResourceGroupName }, { "location", "eastus" }, { "sku", "Standard_LRS" }, { "kind", "StorageV2" } }); // Assert var account = result.AssertProperty("account"); Assert.Equal(JsonValueKind.Object, account.ValueKind); // Check account properties var name = account.GetProperty("name").GetString(); Assert.Equal(uniqueAccountName, name); var location = account.GetProperty("location").GetString(); Assert.Equal("eastus", location); var kind = account.GetProperty("kind").GetString(); Assert.Equal("StorageV2", kind); var skuName = account.GetProperty("skuName").GetString(); Assert.Equal("Standard_LRS", skuName); } [Theory] [InlineData("--invalid-param", new string[0])] [InlineData("--subscription", new[] { "invalidSub" })] [InlineData("--account-name", new[] { "testacct", "--subscription", "sub123" })] // Missing required resource-group and location public async Task Should_Return400_WithInvalidInput_ForAccountCreate(string firstArg, string[] remainingArgs) { var allArgs = new[] { firstArg }.Concat(remainingArgs); var argsString = string.Join(" ", allArgs); // For error testing, we expect CallToolAsync to return null (no results) // and we need to catch any exceptions or check the response manually try { var result = await CallToolAsync("azmcp_storage_account_create", new Dictionary<string, object?> { { "args", argsString } }); // If we get here, the command didn't fail as expected // This might indicate the command succeeded when it should have failed Assert.Fail("Expected command to fail with invalid input, but it succeeded"); } catch (Exception ex) { // Expected to fail with validation errors Assert.True(ex.Message.Contains("required") || ex.Message.Contains("invalid"), $"Expected validation error, but got: {ex.Message}"); } } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Azure/azure-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server