Fix/peek def mac (#170)

* Fix Integrated auth error and Uri for *nix/Mac

* Format code

* Add Logging and unit tests

* Modify tests for Windows:

* Workaround missing default schema on *nix and Mac

* Add unit tests

* Correct comments

* Change loop length

* Fix Log message
This commit is contained in:
Sharon Ravindran
2016-12-07 16:52:35 -08:00
committed by GitHub
parent 4c76b273ec
commit ab97948005
2 changed files with 163 additions and 14 deletions

View File

@@ -6,8 +6,12 @@ using System;
using System.IO;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data.SqlClient;
using System.Runtime.InteropServices;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
@@ -37,9 +41,21 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
if (this.connectionInfo.SqlConnection != null)
{
Server server = new Server(this.connectionInfo.SqlConnection.DataSource);
return server.Databases[this.connectionInfo.SqlConnection.Database];
try
{
// Get server object from connection
string connectionString = ConnectionService.BuildConnectionString(this.connectionInfo.ConnectionDetails);
SqlConnection sqlConn = new SqlConnection(connectionString);
sqlConn.Open();
ServerConnection serverConn = new ServerConnection(sqlConn);
Server server = new Server(serverConn);
return server.Databases[this.connectionInfo.SqlConnection.Database];
}
catch(Exception ex)
{
Logger.Write(LogLevel.Error, "Exception at PeekDefinition Database.get() : " + ex.Message);
return null;
}
}
return null;
}
@@ -83,11 +99,19 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// <summary>
/// Convert a file to a location array containing a location object as expected by the extension
/// </summary>
private Location[] GetLocationFromFile(string tempFileName, int lineNumber)
internal Location[] GetLocationFromFile(string tempFileName, int lineNumber)
{
if (Path.DirectorySeparatorChar.Equals('/'))
{
tempFileName = "file:" + tempFileName;
}
else
{
tempFileName = new Uri(tempFileName).AbsoluteUri;
}
Location[] locations = new[] {
new Location {
Uri = new Uri(tempFileName).AbsoluteUri,
Uri = tempFileName,
Range = new Range {
Start = new Position { Line = lineNumber, Character = 1},
End = new Position { Line = lineNumber + 1, Character = 1}
@@ -135,6 +159,15 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
DeclarationType type = declarationItem.Type;
if (sqlScriptGetters.ContainsKey(type) && sqlObjectTypes.ContainsKey(type))
{
// On *nix and mac systems, the defaultSchema property throws an Exception when accessed.
// This workaround ensures that a schema name is present by attempting
// to get the schema name from the declaration item
// If all fails, the default schema name is assumed to be "dbo"
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && string.IsNullOrEmpty(schemaName))
{
string fullObjectName = declarationItem.DatabaseQualifiedName;
schemaName = this.GetSchemaFromDatabaseQualifiedName(fullObjectName, tokenText);
}
return GetSqlObjectDefinition(
sqlScriptGetters[type],
tokenText,
@@ -148,6 +181,25 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
return null;
}
/// <summary>
/// Return schema name from the full name of the database. If schema is missing return dbo as schema name.
/// </summary>
/// <param name="fullObjectName"> The full database qualified name(database.schema.object)</param>
/// <param name="objectName"> Object name</param>
/// <returns>Schema name</returns>
internal string GetSchemaFromDatabaseQualifiedName(string fullObjectName, string objectName)
{
string[] tokens = fullObjectName.Split('.');
for (int i = tokens.Length - 1; i > 0; i--)
{
if(tokens[i].Equals(objectName))
{
return tokens[i-1];
}
}
return "dbo";
}
/// <summary>
/// Script a table using SMO
/// </summary>

View File

@@ -2,10 +2,11 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.IO;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.IO;
using System;
using System.Runtime.InteropServices;
using Microsoft.SqlServer.Management.SqlParser.Binder;
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Parser;
@@ -46,10 +47,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
private const string OwnerUri = "testFile1";
private const string ViewOwnerUri = "testFile2";
private const string TriggerOwnerUri = "testFile3";
private void InitializeTestObjects()
{
// initial cursor position in the script file
@@ -126,15 +123,74 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
// verify that send result was not called
requestContext.Verify(m => m.SendResult(It.IsAny<Location[]>()), Times.Never());
}
/// <summary>
/// Tests creating location objects on windows and non-windows systems
/// </summary>
[Fact]
public void GetLocationFromFileForValidFilePathTest()
{
String filePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "C:\\test\\script.sql" : "/test/script.sql";
PeekDefinition peekDefinition = new PeekDefinition(null);
Location[] locations = peekDefinition.GetLocationFromFile(filePath, 0);
String expectedFilePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "file:///C:/test/script.sql" : "file:/test/script.sql";
Assert.Equal(locations[0].Uri, expectedFilePath);
}
/// <summary>
/// Test PeekDefinition.GetSchemaFromDatabaseQualifiedName with a valid database name
/// </summary>
[Fact]
public void GetSchemaFromDatabaseQualifiedNameWithValidNameTest()
{
PeekDefinition peekDefinition = new PeekDefinition(null);
string validDatabaseQualifiedName = "master.test.test_table";
string objectName = "test_table";
string expectedSchemaName = "test";
string actualSchemaName = peekDefinition.GetSchemaFromDatabaseQualifiedName(validDatabaseQualifiedName, objectName);
Assert.Equal(actualSchemaName, expectedSchemaName);
}
/// <summary>
/// Test PeekDefinition.GetSchemaFromDatabaseQualifiedName with a valid object name and no schema
/// </summary>
[Fact]
public void GetSchemaFromDatabaseQualifiedNameWithNoSchemaTest()
{
PeekDefinition peekDefinition = new PeekDefinition(null);
string validDatabaseQualifiedName = "test_table";
string objectName = "test_table";
string expectedSchemaName = "dbo";
string actualSchemaName = peekDefinition.GetSchemaFromDatabaseQualifiedName(validDatabaseQualifiedName, objectName);
Assert.Equal(actualSchemaName, expectedSchemaName);
}
/// <summary>
/// Test PeekDefinition.GetSchemaFromDatabaseQualifiedName with a invalid database name
/// </summary>
[Fact]
public void GetSchemaFromDatabaseQualifiedNameWithInvalidNameTest()
{
PeekDefinition peekDefinition = new PeekDefinition(null);
string validDatabaseQualifiedName = "x.y.z";
string objectName = "test_table";
string expectedSchemaName = "dbo";
string actualSchemaName = peekDefinition.GetSchemaFromDatabaseQualifiedName(validDatabaseQualifiedName, objectName);
Assert.Equal(actualSchemaName, expectedSchemaName);
}
#if LIVE_CONNECTION_TESTS
/// <summary>
/// Test get definition for a table object with active connection
/// </summary>
[Fact]
public void GetTableDefinitionTest()
public void GetValidTableDefinitionTest()
{
// Get live connectionInfo
ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition();
@@ -143,11 +199,52 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
string schemaName = null;
string objectType = "TABLE";
// Get locations for valid table object
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetTableScripts, objectName, schemaName, objectType);
Assert.NotNull(locations);
Cleanup(locations);
}
/// <summary>
/// Test get definition for a invalid table object with active connection
/// </summary>
[Fact]
public void GetTableDefinitionInvalidObjectTest()
{
// Get live connectionInfo
ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition();
PeekDefinition peekDefinition = new PeekDefinition(connInfo);
string objectName = "test_invalid";
string schemaName = null;
string objectType = "TABLE";
// Get locations for invalid table object
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetTableScripts, objectName, schemaName, objectType);
Assert.Null(locations);
}
/// <summary>
/// Test get definition for a valid table object with schema and active connection
/// </summary>
[Fact]
public void GetTableDefinitionWithSchemaTest()
{
// Get live connectionInfo
ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition();
PeekDefinition peekDefinition = new PeekDefinition(connInfo);
string objectName = "test_table";
string schemaName = "dbo";
string objectType = "TABLE";
// Get locations for valid table object with schema name
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetTableScripts, objectName, schemaName, objectType);
Assert.NotNull(locations);
Cleanup(locations);
}
/// <summary>
/// Test GetDefinition with an unsupported type(function)
/// </summary>
[Fact]
public void GetUnsupportedDefinitionForFullScript()
{
@@ -177,7 +274,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
/// Test get definition for a view object with active connection
/// </summary>
[Fact]
public void GetViewDefinitionTest()
public void GetValidViewDefinitionTest()
{
ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition();
PeekDefinition peekDefinition = new PeekDefinition(connInfo);