New tool to store SQL connection configs locally (#218)

* added a new tool to store SQL connections locally. Modified the peek definition tests to create test database before running test


* fixed failing test QueryExecutionPlanInvalidParamsTest

* Fixes based on code review comments

* fixed failing test GetSignatureHelpReturnsNotNullIfParseInfoInitialized
This commit is contained in:
Leila Lali
2017-01-25 16:19:27 -08:00
committed by GitHub
parent 5464e4e63a
commit dcff5dd915
30 changed files with 1176 additions and 575 deletions

View File

@@ -4,136 +4,179 @@
//
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.Credentials;
using Microsoft.SqlTools.ServiceLayer.Credentials.Contracts;
using Microsoft.SqlTools.ServiceLayer.TestDriver.Driver;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.Test.Common
{
/// <summary>
/// Service to get connection profiles from the configured settings
/// to get the credentials, test driver will be used if available otherwise the credential service will be called directly
/// credential service will be used to get the credentials
/// </summary>
public class TestConnectionProfileService
{
private readonly IEnumerable<TestServerIdentity> _testServers = TestServersLazyInstance.Value;
private readonly ConnectionSetting _setting = ConnectionSettingLazyInstance.Value;
private static string _connectionSettingsFilename;
private static ConcurrentDictionary<TestServerType, ConnectionProfile> _connectionProfilesCache = new ConcurrentDictionary<TestServerType, ConnectionProfile>();
private static Dictionary<string, InstanceInfo> connectionProfilesCache = new Dictionary<string, InstanceInfo>();
private static TestConnectionProfileService instance = new TestConnectionProfileService();
public TestConnectionProfileService(ServiceTestDriver driver)
public const string DefaultSql2005InstanceKey = "defaultSql2005";
public const string DefaultSql2008InstanceKey = "defaultSql2008";
public const string DefaultSql2011InstanceKey = "defaultSql2011";
public const string DefaultSql2012Pcu1InstanceKey = "defaultSql2012pcu1";
public const string DefaultSql2014InstanceKey = "defaultSql2014";
public const string DefaultSqlAzureInstanceKey = "defaultSqlAzure";
public const string DefaultServerlessInstanceKey = "defaultServerless";
public const string DefaultSqlPdwInstanceKey = "defaultSqlPdw";
public const string DefaultSqlAzureV12InstanceKey = "defaultSqlAzureV12";
public const string DefaultSql2016InstanceKey = "defaultSql2016";
public const string DefaultSqlvNextInstanceKey = "defaultSqlvNext";
private TestConnectionProfileService()
{
Driver = driver;
LoadInstanceSettings();
}
public TestConnectionProfileService()
public static TestConnectionProfileService Instance
{
get
{
return instance;
}
}
private static readonly Lazy<IEnumerable<TestServerIdentity>> TestServersLazyInstance =
new Lazy<IEnumerable<TestServerIdentity>>(InitTestServerNames);
private static readonly Lazy<ConnectionSetting> ConnectionSettingLazyInstance =
new Lazy<ConnectionSetting>(InitSetting);
private ServiceTestDriver Driver { get; set; }
private ConnectionProfile GetConnectionProfile(TestServerType serverType)
public static InstanceInfo DefaultSql2012Pcu1
{
ConnectionProfile connectionProfile = null;
get { return GetInstance(DefaultSql2012Pcu1InstanceKey); }
}
//Get the server or profile name for given type to use for database connection
TestServerIdentity serverIdentity = _testServers != null ? _testServers.FirstOrDefault(x => x.ServerType == serverType) : null;
public static InstanceInfo DefaultSql2014
{
get { return GetInstance(DefaultSql2014InstanceKey); }
}
//Search for the connection info in settings.json
if (serverIdentity == null)
{
//If not server name found, try to find the connection info for given type
connectionProfile = _setting != null && _setting.Connections != null ? _setting.Connections.FirstOrDefault(x => x.ServerType == serverType) : null;
if (connectionProfile == null && _setting != null && _setting.Connections != null)
{
Console.WriteLine(string.Format(CultureInfo.InvariantCulture,
"Cannot find any connection profile for server type '{0}'. "
+ " Make sure the serverType attribute is set in {1}. " +
"Or run CreateTestServerNameSettings.cmd to create a template for the server names", serverType, _connectionSettingsFilename));
}
}
else
{
//Find the connection info for specific server name or profile name
connectionProfile = _setting != null ? _setting.GetConnectionProfile(serverIdentity.ProfileName, serverIdentity.ServerName) : null;
public static InstanceInfo DefaultSqlAzure
{
get { return GetInstance(DefaultSqlAzureInstanceKey); }
}
}
public static InstanceInfo DefaultSqlAzureV12
{
get { return GetInstance(DefaultSqlAzureV12InstanceKey); }
}
Assert.True(connectionProfile != null, "Cannot find any connection profile for server type " + serverType.ToString());
return connectionProfile;
public static InstanceInfo DefaultSql2016
{
get { return GetInstance(DefaultSql2016InstanceKey); }
}
public static InstanceInfo DefaultSqlvNext
{
get { return GetInstance(DefaultSqlvNextInstanceKey); }
}
/// <summary>
/// Returns database connection parameters for given server type
/// Returns the SQL connection info for given version key
/// </summary>
public async Task<ConnectParams> GetConnectionParametersAsync(TestServerType serverType = TestServerType.OnPrem, string databaseName = null)
public static InstanceInfo GetInstance(string key)
{
ConnectionProfile connectionProfile;
if (!_connectionProfilesCache.TryGetValue(serverType, out connectionProfile))
{
connectionProfile = GetConnectionProfile(serverType);
InstanceInfo instanceInfo;
connectionProfilesCache.TryGetValue(key, out instanceInfo);
Assert.True(instanceInfo != null, string.Format(CultureInfo.InvariantCulture, "Cannot find any instance for version key: {0}", key));
return instanceInfo;
}
if (connectionProfile != null)
{
//If the password is empty, get the credential using the service
if (connectionProfile.AuthenticationType == AuthenticationType.SqlLogin && string.IsNullOrEmpty(connectionProfile.Password))
{
Credential credential = await ReadCredentialAsync(connectionProfile.formatCredentialId());
connectionProfile.Password = credential.Password;
}
_connectionProfilesCache.GetOrAdd(serverType, connectionProfile);
}
}
if (connectionProfile != null)
public ConnectParams GetConnectionParameters(string key = DefaultSql2016InstanceKey, string databaseName = null)
{
InstanceInfo instanceInfo = GetInstance(key);
if (instanceInfo != null)
{
ConnectParams connenctParam = CreateConnectParams(connectionProfile, serverType, databaseName);
ConnectParams connenctParam = CreateConnectParams(instanceInfo, key, databaseName);
return connenctParam;
}
return null;
}
/// <summary>
/// Request a Read Credential for given credential id
/// Returns database connection parameters for given server type
/// </summary>
private async Task<Credential> ReadCredentialAsync(string credentialId)
public ConnectParams GetConnectionParameters(TestServerType serverType = TestServerType.OnPrem, string databaseName = null)
{
var credentialParams = new Credential();
credentialParams.CredentialId = credentialId;
string key = ConvertServerTypeToVersionKey(serverType);
return GetConnectionParameters(key, databaseName);
}
ServiceTestDriver driver = Driver;
if (driver == null)
/// <summary>
/// Forces the InstanceManager to load/reload it's instance list
/// </summary>
internal void LoadInstanceSettings()
{
try
{
TestServiceProvider.InitializeTestServices();
return await CredentialService.Instance.ReadCredentialAsync(credentialParams);
connectionProfilesCache = new Dictionary<string, InstanceInfo>();
IEnumerable<TestServerIdentity> testServers = TestConfigPersistenceHelper.InitTestServerNames();
ConnectionSetting settings = TestConfigPersistenceHelper.InitSetting();
if (settings == null)
{
Console.WriteLine("DBTestInstance not configured. Run 'dotnet run Microsoft.SqlTools.ServiceLayer.TestEnvConfig from the command line to configure");
}
if (testServers != null && settings != null)
{
foreach (var serverIdentity in testServers)
{
var instance = settings != null ? settings.GetConnectionProfile(serverIdentity.ProfileName, serverIdentity.ServerName) : null;
if (instance.ServerType == TestServerType.None)
{
instance.ServerType = serverIdentity.ServerType;
AddInstance(instance);
}
}
}
if (settings != null)
{
foreach (var instance in settings.Connections)
{
AddInstance(instance);
}
}
}
else
catch(Exception ex)
{
return await Driver.SendRequest(ReadCredentialRequest.Type, credentialParams);
Assert.True(false, "Fail to load the SQL connection instances. error: " + ex.Message);
}
}
private static void AddInstance(InstanceInfo instance)
{
if (instance != null && (instance.ServerType != TestServerType.None || !string.IsNullOrEmpty(instance.VersionKey)))
{
TestServerType serverType = instance.ServerType == TestServerType.None ? TestServerType.OnPrem : instance.ServerType; //Default to onPrem
string versionKey = string.IsNullOrEmpty(instance.VersionKey) ? ConvertServerTypeToVersionKey(serverType) : instance.VersionKey;
if (!connectionProfilesCache.ContainsKey(versionKey))
{
//If the password is empty, get the credential using the service
if (instance.AuthenticationType == AuthenticationType.SqlLogin && string.IsNullOrEmpty(instance.Password))
{
Credential credential = TestCredentialService.Instance.ReadCredential(instance);
instance.Password = credential.Password;
}
connectionProfilesCache.Add(versionKey, instance);
}
}
}
private static string ConvertServerTypeToVersionKey(TestServerType serverType)
{
return serverType == TestServerType.OnPrem ? DefaultSql2016InstanceKey : DefaultSqlAzureV12InstanceKey;
}
/// <summary>
/// Create a connection parameters object
/// </summary>
private ConnectParams CreateConnectParams(ConnectionProfile connectionProfile, TestServerType serverType, string databaseName)
private ConnectParams CreateConnectParams(InstanceInfo connectionProfile, string key, string databaseName)
{
ConnectParams connectParams = new ConnectParams();
connectParams.Connection = new ConnectionDetails();
@@ -146,7 +189,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
{
connectParams.Connection.DatabaseName = databaseName;
}
if (serverType == TestServerType.Azure)
if (key == DefaultSqlAzureInstanceKey || key == DefaultSqlAzureV12InstanceKey)
{
connectParams.Connection.ConnectTimeout = 30;
connectParams.Connection.Encrypt = true;
@@ -154,112 +197,5 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
}
return connectParams;
}
private static IEnumerable<TestServerIdentity> InitTestServerNames()
{
try
{
string testServerNamesFileContent = GetTestServerNamesFileContent();
if (!string.IsNullOrEmpty(testServerNamesFileContent))
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<IList<TestServerIdentity>>(testServerNamesFileContent);
}
else
{
return Enumerable.Empty<TestServerIdentity>();
}
}
catch (Exception ex)
{
Console.WriteLine("Failed to load the database connection server name settings. error: " + ex.Message);
return Enumerable.Empty<TestServerIdentity>();
}
}
private static ConnectionSetting InitSetting()
{
try
{
string settingsFileContents = GetSettingFileContent();
ConnectionSetting setting = Newtonsoft.Json.JsonConvert.DeserializeObject<ConnectionSetting>(settingsFileContents);
Console.WriteLine("Connection Settings loaded successfully");
return setting;
}
catch (Exception ex)
{
Console.WriteLine("Failed to load the connection settings. error: " + ex.Message);
return new ConnectionSetting();
}
}
/// <summary>
/// Get the location of testServerNames.json. Returns the value of environment variable 'SettingsFileName' and if it's empty returns
/// the location of vs code testServerNames.json
/// </summary>
/// <returns></returns>
private static string GetTestServerNamesFileContent()
{
var testServerNameFilePath = Environment.GetEnvironmentVariable("TestServerNamesFile");
string testServerFileName = "testServerNames.json";
if (string.IsNullOrEmpty(testServerNameFilePath))
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
testServerNameFilePath = Environment.GetEnvironmentVariable("APPDATA") + @"\\" + testServerFileName;
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
testServerNameFilePath = Environment.GetEnvironmentVariable("HOME") + @"/" + testServerFileName;
}
else
{
testServerNameFilePath = Environment.GetEnvironmentVariable("HOME") + @"/" + testServerFileName;
}
}
string testServerNamesFileContent = string.IsNullOrEmpty(testServerNameFilePath) ? string.Empty : File.ReadAllText(testServerNameFilePath);
return testServerNamesFileContent;
}
/// <summary>
/// Get the location of setting.json. Returns the value of environment variable 'SettingsFileName' and if it's empty returns
/// the location of vs code settings.json
/// </summary>
/// <returns></returns>
private static string GetSettingFileContent()
{
var settingsFilename = Environment.GetEnvironmentVariable("SettingsFileName");
if (string.IsNullOrEmpty(settingsFilename))
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
settingsFilename = Environment.GetEnvironmentVariable("APPDATA") + @"\Code\User\settings.json";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
settingsFilename = Environment.GetEnvironmentVariable("HOME") + @"/Library/Application Support/Code/User/settings.json";
}
else
{
settingsFilename = Environment.GetEnvironmentVariable("HOME") + @"/.config/Code/User/settings.json";
}
}
if (string.IsNullOrEmpty(settingsFilename))
{
Console.WriteLine("Cannot find any connection settings. Please run CreateConnectionSettings.cmd to generate a template for the connection settings.");
}
else
{
Console.WriteLine("Connection settings: " + settingsFilename);
_connectionSettingsFilename = settingsFilename;
}
string settingsFileContents = string.IsNullOrEmpty(settingsFilename) ? string.Empty : File.ReadAllText(settingsFilename);
return settingsFileContents;
}
}
}