diff --git a/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/CapabilitiesRequest.cs b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/CapabilitiesRequest.cs new file mode 100644 index 00000000..20cd0789 --- /dev/null +++ b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/CapabilitiesRequest.cs @@ -0,0 +1,29 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.SqlTools.Hosting.Contracts +{ + /// + /// Defines a message that is sent from the client to request + /// the version of the server. + /// + public class CapabilitiesRequest + { + public static readonly + RequestType Type = + RequestType.Create("capabilities/list"); + + public string HostName { get; set; } + + public string HostVersion { get; set; } + } + + public class CapabilitiesResult + { + public DmpServerCapabilities Capabilities { get; set; } + } +} diff --git a/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/ConnectionProviderOptions.cs b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/ConnectionProviderOptions.cs new file mode 100644 index 00000000..066f0827 --- /dev/null +++ b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/ConnectionProviderOptions.cs @@ -0,0 +1,67 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.SqlTools.Hosting.Contracts +{ + /// + /// Defines the connection provider options that the DMP server + /// implements. This includes metadata regarding supported connection + /// properties. + /// + public class ConnectionProviderOptions + { + public ConnectionOption[] Options { get; set; } + } + + public class ConnectionOption + { + public static readonly string ValueTypeString = "string"; + public static readonly string ValueTypeMultiString = "multistring"; + public static readonly string ValueTypePassword = "password"; + public static readonly string ValueTypeNumber = "number"; + public static readonly string ValueTypeCategory = "category"; + public static readonly string ValueTypeBoolean = "boolean"; + + public static readonly string SpecialValueServerName = "serverName"; + public static readonly string SpecialValueDatabaseName = "databaseName"; + public static readonly string SpecialValueAuthType = "authType"; + public static readonly string SpecialValueUserName = "userName"; + public static readonly string SpecialValuePasswordName = "password"; + + public string Name { get; set; } + + public string DisplayName { get; set; } + + /// + /// Type of the parameter. Can be either string, number, or category. + /// + public string ValueType { get; set; } + + public string DefaultValue { get; set; } + + /// + /// Set of permitted values if ValueType is category. + /// + public string[] CategoryValues { get; set; } + + /// + /// Determines if the parameter is one of the 'specical' known values. + /// Can be either Server Name, Database Name, Authentication Type, + /// User Name, or Password + /// + public string SpecialValueType { get; set; } + + /// + /// Flag to indicate that this option is part of the connection identity + /// + public bool IsIdentity { get; set; } + + /// + /// Flag to indicate that this option is required + /// + public bool IsRequired { get; set; } + } +} + diff --git a/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/DmpServerCapabilities.cs b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/DmpServerCapabilities.cs index d38efe0f..9b204021 100644 --- a/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/DmpServerCapabilities.cs +++ b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/DmpServerCapabilities.cs @@ -5,11 +5,17 @@ namespace Microsoft.SqlTools.Hosting.Contracts { + /// + /// Defines the DMP server capabilities + /// public class DmpServerCapabilities { - public string ProviderName { get; set; - } - public bool? HoverProvider { get; set; } + public string ProtocolVersion { get; set; } + + public string ProviderName { get; set; } + + public string ProviderDisplayName { get; set; } + + public ConnectionProviderOptions ConnectionProvider { get; set; } } } - diff --git a/src/Microsoft.SqlTools.ServiceLayer/ServiceHost.cs b/src/Microsoft.SqlTools.ServiceLayer/ServiceHost.cs index 1bddc4cb..615f648f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ServiceHost.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ServiceHost.cs @@ -62,8 +62,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting public void InitializeRequestHandlers() { // Register the requests that this service host will handle - this.SetRequestHandler(InitializeRequest.Type, this.HandleInitializeRequest); - this.SetRequestHandler(ShutdownRequest.Type, this.HandleShutdownRequest); + this.SetRequestHandler(InitializeRequest.Type, HandleInitializeRequest); + this.SetRequestHandler(CapabilitiesRequest.Type, HandleCapabilitiesRequest); + this.SetRequestHandler(ShutdownRequest.Type, HandleShutdownRequest); this.SetRequestHandler(VersionRequest.Type, HandleVersionRequest); } @@ -171,6 +172,140 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting }); } + internal async Task HandleCapabilitiesRequest( + CapabilitiesRequest initializeParams, + RequestContext requestContext) + { + await requestContext.SendResult( + new CapabilitiesResult + { + Capabilities = new DmpServerCapabilities + { + ProtocolVersion = "1.0", + ProviderName = "MSSQL", + ProviderDisplayName = "Microsoft SQL Server", + ConnectionProvider = ServiceHost.BuildConnectionProviderOptions() + } + } + ); + } + + private static ConnectionProviderOptions BuildConnectionProviderOptions() + { + return new ConnectionProviderOptions + { + Options = new ConnectionOption[] + { + new ConnectionOption + { + Name = "Server Name", + ValueType = ConnectionOption.ValueTypeString, + SpecialValueType = ConnectionOption.SpecialValueServerName, + IsIdentity = true, + IsRequired = true + }, + new ConnectionOption + { + Name = "Initial Catalog", + DisplayName = "Database Name", + ValueType = ConnectionOption.ValueTypeString, + SpecialValueType = ConnectionOption.SpecialValueDatabaseName, + IsIdentity = true, + IsRequired = true + }, + new ConnectionOption + { + Name = "Auth Type", + ValueType = ConnectionOption.ValueTypeCategory, + SpecialValueType = ConnectionOption.SpecialValueAuthType, + CategoryValues = new string[] { "SQL Login", "Integrated Auth" }, + IsIdentity = true, + IsRequired = true + }, + new ConnectionOption + { + Name = "Username", + ValueType = ConnectionOption.ValueTypeString, + SpecialValueType = ConnectionOption.SpecialValueUserName, + IsIdentity = true, + IsRequired = true + }, + new ConnectionOption + { + Name = "Password", + DisplayName = "Database Name", + ValueType = ConnectionOption.ValueTypePassword, + SpecialValueType = ConnectionOption.SpecialValuePasswordName, + IsIdentity = true, + IsRequired = true + }, + new ConnectionOption + { + Name = "Application Intent", + ValueType = ConnectionOption.ValueTypeCategory, + CategoryValues = new string[] { "ReadWrite", "ReadOnly" } + }, + new ConnectionOption + { + Name = "Asynchronous Processing", + ValueType = ConnectionOption.ValueTypeBoolean + }, + new ConnectionOption + { + Name = "Connect Timeout", + ValueType = ConnectionOption.ValueTypeNumber, + DefaultValue = "15" + }, + new ConnectionOption + { + Name = "Current Language", + ValueType = ConnectionOption.ValueTypeString + }, + new ConnectionOption + { + Name = "Column Encrytion Setting", + ValueType = ConnectionOption.ValueTypeCategory, + CategoryValues = new string[] { "Disabled", "Enabled" } + }, + new ConnectionOption + { + Name = "Encrypt", + ValueType = ConnectionOption.ValueTypeBoolean + }, + new ConnectionOption + { + Name = "Persist Security Info", + ValueType = ConnectionOption.ValueTypeBoolean + }, + new ConnectionOption + { + Name = "Trust Server Certificate", + ValueType = ConnectionOption.ValueTypeBoolean + }, + new ConnectionOption + { + Name = "Persist Security Info", + ValueType = ConnectionOption.ValueTypeBoolean + }, + new ConnectionOption + { + Name = "Trust Server Certificate", + ValueType = ConnectionOption.ValueTypeBoolean + }, + new ConnectionOption + { + Name = "Attached DB File Name", + ValueType = ConnectionOption.ValueTypeString + }, + new ConnectionOption + { + Name = "Context Connection", + ValueType = ConnectionOption.ValueTypeString + } + } + }; + } + /// /// Handles the version request. Sends back the server version as result. /// diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ServiceHost/CapabilitiesTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ServiceHost/CapabilitiesTests.cs new file mode 100644 index 00000000..04cfb80a --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ServiceHost/CapabilitiesTests.cs @@ -0,0 +1,35 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Threading.Tasks; +using Microsoft.SqlTools.Hosting.Contracts; +using Microsoft.SqlTools.Hosting.Protocol; +using Moq; +using Xunit; + +namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Capabilities +{ + /// + /// Test cases for the capabilities discovery messages + /// + public class Capabilities + { + [Fact] + public async Task TestCapabilities() + { + Hosting.ServiceHost host = Hosting.ServiceHost.Instance; + var requestContext = new Mock>(); + requestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object())); + + await host.HandleCapabilitiesRequest(new CapabilitiesRequest + { + HostName = "Test Host", HostVersion = "1.0" + }, requestContext.Object); + + requestContext.Verify(x => x.SendResult(It.Is( + i => i.Capabilities.ConnectionProvider.Options != null))); + } + } +}