diff --git a/CosmosDBShell.Tests/CommandTests/ConnectCommandTests.cs b/CosmosDBShell.Tests/CommandTests/ConnectCommandTests.cs index db40cef..9e16836 100644 --- a/CosmosDBShell.Tests/CommandTests/ConnectCommandTests.cs +++ b/CosmosDBShell.Tests/CommandTests/ConnectCommandTests.cs @@ -68,6 +68,32 @@ public void ConnectCommand_VSCodeCredentialOption_DoesNotProduceUnknownOptionDia Assert.DoesNotContain(model.Diagnostics, diagnostic => diagnostic.Code == "SEM002"); } + [Fact] + public void LocalEmulatorConnectionFailureMessage_ExplainsCommonCauses() + { + var endpoint = new Uri("https://localhost:8081/"); + var message = ShellInterpreter.GetLocalEmulatorConnectionFailureMessage(endpoint); + + Assert.Contains("Cosmos DB emulator at https://localhost:8081/", message, StringComparison.OrdinalIgnoreCase); + Assert.Contains("http://localhost:8081/", message, StringComparison.OrdinalIgnoreCase); + Assert.Contains("--protocol [https|http]", message, StringComparison.OrdinalIgnoreCase); + Assert.Contains("https://learn.microsoft.com/en-us/azure/cosmos-db/emulator-linux", message, StringComparison.OrdinalIgnoreCase); + Assert.Contains("docker ps", message, StringComparison.OrdinalIgnoreCase); + Assert.Contains("http://localhost:8080/alive", message, StringComparison.OrdinalIgnoreCase); + Assert.Contains("mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator", message, StringComparison.OrdinalIgnoreCase); + Assert.Contains("docker run", message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void LocalEmulatorConnectionFailureMessage_SuggestsHttpsWhenHttpFails() + { + var endpoint = new Uri("http://localhost:8081/"); + var message = ShellInterpreter.GetLocalEmulatorConnectionFailureMessage(endpoint); + + Assert.Contains("Cosmos DB emulator at http://localhost:8081/", message, StringComparison.OrdinalIgnoreCase); + Assert.Contains("https://localhost:8081/", message, StringComparison.OrdinalIgnoreCase); + } + private static async Task BindConnectCommandAsync(string commandText) { var parser = new StatementParser(commandText); diff --git a/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs b/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs index 594ecb5..2aaa598 100644 --- a/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs +++ b/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs @@ -641,6 +641,11 @@ internal async Task ConnectAsync(string connectionString, string? loginHint = nu catch (Exception ex) { client.Dispose(); + if (isEmulator) + { + throw new ShellException(GetLocalEmulatorConnectionFailureMessage(client.Endpoint), ex); + } + throw new ShellException(MessageService.GetString("error-connection_failed"), ex); } @@ -903,6 +908,28 @@ private static async Task ReadAccountAsync(CosmosClient clien return await client.ReadAccountAsync().WaitAsync(token); } + internal static string GetLocalEmulatorConnectionFailureMessage(Uri endpoint) + { + var alternate = BuildAlternateEmulatorUri(endpoint); + return MessageService.GetArgsString( + "error-emulator_connection_failed", + "endpoint", + endpoint.ToString(), + "alternate", + alternate.ToString()); + } + + private static Uri BuildAlternateEmulatorUri(Uri endpoint) + { + var builder = new UriBuilder(endpoint) + { + Scheme = string.Equals(endpoint.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) + ? Uri.UriSchemeHttp + : Uri.UriSchemeHttps, + }; + return builder.Uri; + } + /// /// Connects to a client & disposes old state. /// diff --git a/CosmosDBShell/lang/en.ftl b/CosmosDBShell/lang/en.ftl index 50c60b8..cd45a49 100644 --- a/CosmosDBShell/lang/en.ftl +++ b/CosmosDBShell/lang/en.ftl @@ -20,6 +20,15 @@ no_char = N error = Error: error-connection_failed = Failed to connect to the Cosmos DB account. +error-emulator_connection_failed = + Could not reach the Cosmos DB emulator at { $endpoint }. + Make sure the emulator container is running ('docker ps') and reachable. + Tip: the Linux emulator exposes a health probe at http://localhost:8080/alive that can be used to verify it is up. + The Cosmos DB SDKs (including this shell) require HTTPS, but the Linux emulator defaults to HTTP. + Restart the container with --protocol [https|http], for example: + docker run -d -p 8081:8081 -p 1234:1234 -p 8080:8080 mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview --protocol https + Or, if you intentionally started the emulator with the other protocol, try connecting to { $alternate } instead. + See: https://learn.microsoft.com/en-us/azure/cosmos-db/emulator-linux error-command-not-found = '{ $command }' is not recognized as an internal or external command, operable program or batch file. error-shell-not-initialized = Shell is not initialized error-start_process = Failed to start the process.