Implemented the oe filtering (#328)

* Implemented the oe filtering
This commit is contained in:
Leila Lali
2017-04-26 14:48:17 -07:00
committed by GitHub
parent 1a16101381
commit 51916c2221
17 changed files with 3108 additions and 1030 deletions

View File

@@ -1,14 +1,15 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
// 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.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
@@ -22,78 +23,95 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer
{
private ObjectExplorerService _service = TestServiceProvider.Instance.ObjectExplorerService;
[Fact]
public async void CreateSessionAndExpandOnTheServerShouldReturnServerAsTheRoot()
{
var query = "";
string uri = "CreateSessionAndExpandServer";
string databaseName = null;
[Fact]
public async void CreateSessionAndExpandOnTheServerShouldReturnServerAsTheRoot()
{
var query = "";
string uri = "CreateSessionAndExpandServer";
string databaseName = null;
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri))
{
var session = await CreateSession(null, uri);
await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
CancelConnection(uri);
}
CancelConnection(uri);
}
[Fact]
public async void CreateSessionWithTempdbAndExpandOnTheServerShouldReturnServerAsTheRoot()
{
var query = "";
string uri = "CreateSessionAndExpandServer";
string databaseName = null;
[Fact]
public async void CreateSessionWithTempdbAndExpandOnTheServerShouldReturnServerAsTheRoot()
{
var query = "";
string uri = "CreateSessionAndExpandServer";
string databaseName = null;
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri))
{
var session = await CreateSession("tempdb", uri);
await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
CancelConnection(uri);
}
CancelConnection(uri);
}
[Fact]
public async void CreateSessionAndExpandOnTheDatabaseShouldReturnDatabaseAsTheRoot()
{
var query = "";
string uri = "CreateSessionAndExpandDatabase";
string databaseName = null;
public async void CreateSessionAndExpandOnTheDatabaseShouldReturnDatabaseAsTheRoot()
{
var query = "";
string uri = "CreateSessionAndExpandDatabase";
string databaseName = null;
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri))
{
var session = await CreateSession(testDb.DatabaseName, uri);
ExpandAndVerifyDatabaseNode(testDb.DatabaseName, session);
CancelConnection(uri);
}
CancelConnection(uri);
}
private async Task<ObjectExplorerSession> CreateSession(string databaseName, string uri)
{
ConnectParams connectParams = TestServiceProvider.Instance.ConnectionProfileService.GetConnectionParameters(TestServerType.OnPrem, databaseName);
connectParams.Connection.Pooling = false;
ConnectionDetails details = connectParams.Connection;
return await _service.DoCreateSession(details, uri);
var session = await _service.DoCreateSession(details, uri);
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "OE session created for database: {0}", databaseName));
return session;
}
private async Task<NodeInfo> ExpandServerNodeAndVerifyDatabaseHierachy(string databaseName, ObjectExplorerSession session)
private async Task<NodeInfo> ExpandServerNodeAndVerifyDatabaseHierachy(string databaseName, ObjectExplorerSession session, bool serverNode = true)
{
Assert.NotNull(session);
Assert.NotNull(session.Root);
NodeInfo nodeInfo = session.Root.ToNodeInfo();
Assert.Equal(nodeInfo.IsLeaf, false);
Assert.Equal(nodeInfo.NodeType, NodeTypes.Server.ToString());
var children = session.Root.Expand();
NodeInfo databaseNode = null;
//All server children should be folder nodes
foreach (var item in children)
if (serverNode)
{
Assert.Equal(item.NodeType, "Folder");
Assert.Equal(nodeInfo.NodeType, NodeTypes.Server.ToString());
var children = session.Root.Expand();
//All server children should be folder nodes
foreach (var item in children)
{
Assert.Equal(item.NodeType, "Folder");
}
var databasesRoot = children.FirstOrDefault(x => x.NodeTypeId == NodeTypes.Databases);
var databasesChildren = await _service.ExpandNode(session, databasesRoot.GetNodePath());
var databases = databasesChildren.Where(x => x.NodeType == NodeTypes.Database.ToString());
//Verify the test databases is in the list
Assert.NotNull(databases);
databaseNode = databases.FirstOrDefault(d => d.Label == databaseName);
}
else
{
Assert.Equal(nodeInfo.NodeType, NodeTypes.Database.ToString());
databaseNode = session.Root.ToNodeInfo();
Assert.True(databaseNode.Label.Contains(databaseName));
}
var databasesRoot = children.FirstOrDefault(x => x.NodeTypeId == NodeTypes.Databases);
var databasesChildren = await _service.ExpandNode(session, databasesRoot.GetNodePath());
var databases = databasesChildren.Where(x => x.NodeType == NodeTypes.Database.ToString());
//Verify the test databases is in the list
Assert.NotNull(databases);
var databaseNode = databases.FirstOrDefault(d => d.Label == databaseName);
Assert.NotNull(databaseNode);
return databaseNode;
}
@@ -120,154 +138,212 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer
private void CancelConnection(string uri)
{
//ConnectionService.Instance.CancelConnect(new CancelConnectParams
//{
// OwnerUri = uri,
// Type = ConnectionType.Default
//});
ConnectionService.Instance.CancelConnect(new CancelConnectParams
{
OwnerUri = uri,
Type = ConnectionType.Default
});
}
private async Task ExpandTree(NodeInfo node, ObjectExplorerSession session)
{
if(node != null && !node.IsLeaf)
if (node != null && !node.IsLeaf)
{
var children = await _service.ExpandNode(session, node.NodePath);
Assert.NotNull(children);
if(!node.NodePath.Contains("System") &&
!node.NodePath.Contains("FileTables") && !node.NodePath.Contains("External Tables"))
{
var labaleToUpper = node.Label.ToUpper();
foreach (var child in children)
{
if (child.NodeType != "Folder")
{
Assert.NotNull(child.NodeType);
if (child.Metadata != null && !string.IsNullOrEmpty(child.Metadata.MetadataTypeName))
{
if (!string.IsNullOrEmpty(child.Metadata.Schema))
{
Assert.Equal($"{child.Metadata.Schema}.{child.Metadata.Name}", child.Label);
}
else
{
Assert.Equal(child.Metadata.Name, child.Label);
}
}
else
{
}
}
}
}
foreach (var child in children)
{
//Console.WriteLine(child.Label);
await ExpandTree(child, session);
await _service.ExpandNode(session, child.NodePath);
}
}
}
/// <summary>
/// Returns the children of a node with the given label
/// </summary>
private async Task<NodeInfo[]> FindNodeByLabel(NodeInfo node, ObjectExplorerSession session, string nodeType, bool nodeFound = false)
{
if (node != null && !node.IsLeaf)
{
var children = await _service.ExpandNode(session, node.NodePath);
Assert.NotNull(children);
if (!nodeFound)
{
foreach (var child in children)
{
VerifyMetadata(child);
if (child.Label == nodeType)
{
return await FindNodeByLabel(child, session, nodeType, true);
}
var result = await FindNodeByLabel(child, session, nodeType);
if (result != null)
{
return result;
}
}
}
else
{
return children;
}
}
return null;
}
private void VerifyMetadata(NodeInfo node)
{
if (node.NodeType != "Folder")
{
Assert.NotNull(node.NodeType);
if (node.Metadata != null && !string.IsNullOrEmpty(node.Metadata.MetadataTypeName))
{
if (!string.IsNullOrEmpty(node.Metadata.Schema))
{
Assert.Equal($"{node.Metadata.Schema}.{node.Metadata.Name}", node.Label);
}
else
{
Assert.Equal(node.Metadata.Name, node.Label);
}
}
}
}
[Fact]
public async void VerifyAdventureWorksDatabaseObjects()
{
var query = Scripts.AdventureWorksScript;
string uri = "VerifyAdventureWorksDatabaseObjects";
string databaseName = null;
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri))
var query = Scripts.AdventureWorksScript;
string uri = "VerifyAdventureWorksDatabaseObjects";
string databaseName = null;
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, true, databaseName, query, uri))
{
var session = await CreateSession(null, uri);
var databaseNodeInfo = await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
await ExpandTree(databaseNodeInfo, session);
CancelConnection(uri);
var session = await CreateSession(testDb.DatabaseName, queryTempFile.FilePath);
var databaseNodeInfo = await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session, false);
await ExpandTree(session.Root.ToNodeInfo(), session);
var tablesChildren = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_Tables);
var systemTables = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_SystemTables);
Assert.True(!systemTables.Any());
var externalTables = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_ExternalTables);
Assert.True(!externalTables.Any());
var fileTables = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_FileTables);
Assert.True(!fileTables.Any());
var allTables = tablesChildren.Where(x => x.NodeType != NodeTypes.Folder.ToString());
Assert.True(allTables.Any());
var storedProcedures = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_StoredProcedures);
Assert.True(storedProcedures.Any());
var views = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_Views);
Assert.True(views.Any());
var userDefinedDataTypes = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_UserDefinedDataTypes);
Assert.True(userDefinedDataTypes.Any());
var scalarValuedFunctions = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_ScalarValuedFunctions);
Assert.True(scalarValuedFunctions.Any());
}
CancelConnection(uri);
}
// [Fact]
// [Fact]
public async void VerifySql2016Objects()
{
var query = LoadScript("Sql_2016_Additions.sql");
string uri = "VerifySql2016Objects";
string databaseName = null;
var query = LoadScript("Sql_2016_Additions.sql");
string uri = "VerifySql2016Objects";
string databaseName = null;
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri))
{
var session = await CreateSession(testDb.DatabaseName, uri);
var databaseNodeInfo = await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
await ExpandTree(databaseNodeInfo, session);
CancelConnection(uri);
await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_Tables);
}
CancelConnection(uri);
}
// [Fact]
// [Fact]
public async void VerifySqlObjects()
{
var query = LoadScript("Sql_Additions.sql");
string uri = "VerifySqlObjects";
string databaseName = null;
var query = LoadScript("Sql_Additions.sql");
string uri = "VerifySqlObjects";
string databaseName = null;
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri))
{
var session = await CreateSession(testDb.DatabaseName, uri);
var databaseNodeInfo = await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
await ExpandTree(databaseNodeInfo, session);
CancelConnection(uri);
await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_Tables);
}
CancelConnection(uri);
}
// [Fact]
// [Fact]
public async void VerifyFileTableTest()
{
var query = LoadScript("FileTableTest.sql");
string uri = "VerifyFileTableTest";
string databaseName = null;
var query = LoadScript("FileTableTest.sql");
string uri = "VerifyFileTableTest";
string databaseName = null;
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri))
{
var session = await CreateSession(testDb.DatabaseName, uri);
var databaseNodeInfo = await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
await ExpandTree(databaseNodeInfo, session);
CancelConnection(uri);
await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_Tables);
}
CancelConnection(uri);
}
//[Fact]
public async void VerifyColumnstoreindexSql16()
{
var query = LoadScript("ColumnstoreindexSql16.sql");
string uri = "VerifyColumnstoreindexSql16";
string databaseName = null;
var query = LoadScript("ColumnstoreindexSql16.sql");
string uri = "VerifyColumnstoreindexSql16";
string databaseName = null;
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri))
{
var session = await CreateSession(testDb.DatabaseName, uri);
var databaseNodeInfo = await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
await ExpandTree(databaseNodeInfo, session);
CancelConnection(uri);
await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_Tables);
}
CancelConnection(uri);
}
private static string TestLocationDirectory
{
get
{
return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), "ObjectExplorer");
}
}
private static string TestLocationDirectory
{
get
{
return Path.Combine(RunEnvironmentInfo.GetTestDataLocation(), "ObjectExplorer");
}
public DirectoryInfo InputFileDirectory
{
get
{
string d = Path.Combine(TestLocationDirectory, "TestScripts");
return new DirectoryInfo(d);
}
}
public DirectoryInfo InputFileDirectory
{
get
{
string d = Path.Combine(TestLocationDirectory, "TestScripts");
return new DirectoryInfo(d);
}
}
public FileInfo GetInputFile(string fileName)
{
return new FileInfo(Path.Combine(InputFileDirectory.FullName, fileName));
public FileInfo GetInputFile(string fileName)
{
return new FileInfo(Path.Combine(InputFileDirectory.FullName, fileName));
}
private string LoadScript(string fileName)

View File

@@ -113,12 +113,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
{
if (!DoNotCleanupDb)
{
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
{
string dropDatabaseQuery = string.Format(CultureInfo.InvariantCulture,
string dropDatabaseQuery = string.Format(CultureInfo.InvariantCulture,
(ServerType == TestServerType.Azure ? Scripts.DropDatabaseIfExistAzure : Scripts.DropDatabaseIfExist), DatabaseName);
TestServiceProvider.Instance.RunQuery(ServerType, MasterDatabaseName, dropDatabaseQuery);
}
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Cleaning up database {0}", DatabaseName));
TestServiceProvider.Instance.RunQuery(ServerType, MasterDatabaseName, dropDatabaseQuery);
}
}

View File

@@ -184,6 +184,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
connectParams.Connection.DatabaseName = connectionProfile.Database;
connectParams.Connection.UserName = connectionProfile.User;
connectParams.Connection.Password = connectionProfile.Password;
connectParams.Connection.MaxPoolSize = 200;
connectParams.Connection.AuthenticationType = connectionProfile.AuthenticationType.ToString();
if (!string.IsNullOrEmpty(databaseName))
{

View File

@@ -1,369 +1,369 @@
//
// 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.Collections.Generic;
using System.Data.SqlClient;
using System.Globalization;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.Extensibility;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel;
using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility;
using Moq;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
{
/// <summary>
/// Tests covering basic operation of Node based classes
/// </summary>
public class NodeTests : ObjectExplorerTestBase
{
private string defaultOwnerUri = "objectexplorer://myserver";
private ServerInfo defaultServerInfo;
private ConnectionDetails defaultConnectionDetails;
private ConnectionCompleteParams defaultConnParams;
private string fakeConnectionString = "Data Source=server;Initial Catalog=database;Integrated Security=False;User Id=user";
public NodeTests()
{
defaultServerInfo = TestObjects.GetTestServerInfo();
defaultConnectionDetails = new ConnectionDetails()
{
DatabaseName = "master",
ServerName = "localhost",
UserName = "serverAdmin",
Password = "..."
};
defaultConnParams = new ConnectionCompleteParams()
{
ServerInfo = defaultServerInfo,
ConnectionSummary = defaultConnectionDetails,
OwnerUri = defaultOwnerUri
};
// TODO can all tests use the standard service provider?
ServiceProvider = ExtensionServiceProvider.CreateDefaultServiceProvider();
}
[Fact]
public void ServerNodeConstructorValidatesFields()
{
Assert.Throws<ArgumentNullException>(() => new ServerNode(null, ServiceProvider));
Assert.Throws<ArgumentNullException>(() => new ServerNode(defaultConnParams, null));
}
[Fact]
public void ServerNodeConstructorShouldSetValuesCorrectly()
{
// Given a server node with valid inputs
ServerNode node = new ServerNode(defaultConnParams, ServiceProvider);
// Then expect all fields set correctly
Assert.False(node.IsAlwaysLeaf, "Server node should never be a leaf");
Assert.Equal(defaultConnectionDetails.ServerName, node.NodeValue);
string expectedLabel = defaultConnectionDetails.ServerName + " (SQL Server " + defaultServerInfo.ServerVersion + " - "
+ defaultConnectionDetails.UserName + ")";
Assert.Equal(expectedLabel, node.Label);
Assert.Equal(NodeTypes.Server.ToString(), node.NodeType);
string[] nodePath = node.GetNodePath().Split(TreeNode.PathPartSeperator);
Assert.Equal(1, nodePath.Length);
Assert.Equal(defaultConnectionDetails.ServerName, nodePath[0]);
}
[Fact]
public void ServerNodeLabelShouldIgnoreUserNameIfEmptyOrNull()
{
// Given no username set
ConnectionSummary integratedAuthSummary = new ConnectionSummary()
{
DatabaseName = defaultConnectionDetails.DatabaseName,
ServerName = defaultConnectionDetails.ServerName,
UserName = null
};
ConnectionCompleteParams connParams = new ConnectionCompleteParams()
{
ConnectionSummary = integratedAuthSummary,
ServerInfo = defaultServerInfo,
OwnerUri = defaultOwnerUri
};
// When querying label
string label = new ServerNode(connParams, ServiceProvider).Label;
// Then only server name and version shown
string expectedLabel = defaultConnectionDetails.ServerName + " (SQL Server " + defaultServerInfo.ServerVersion + ")";
Assert.Equal(expectedLabel, label);
}
[Fact]
public void ServerNodeConstructorShouldShowDbNameForCloud()
{
defaultServerInfo.IsCloud = true;
// Given a server node for a cloud DB, with master name
ServerNode node = new ServerNode(defaultConnParams, ServiceProvider);
// Then expect label to not include db name
string expectedLabel = defaultConnectionDetails.ServerName + " (SQL Server " + defaultServerInfo.ServerVersion + " - "
+ defaultConnectionDetails.UserName + ")";
Assert.Equal(expectedLabel, node.Label);
// But given a server node for a cloud DB that's not master
defaultConnectionDetails.DatabaseName = "NotMaster";
node = new ServerNode(defaultConnParams, ServiceProvider);
// Then expect label to include db name
expectedLabel = defaultConnectionDetails.ServerName + " (SQL Server " + defaultServerInfo.ServerVersion + " - "
+ defaultConnectionDetails.UserName + ", " + defaultConnectionDetails.DatabaseName + ")";
Assert.Equal(expectedLabel, node.Label);
}
[Fact]
public void ToNodeInfoIncludeAllFields()
{
// Given a server connection
ServerNode node = new ServerNode(defaultConnParams, ServiceProvider);
// When converting to NodeInfo
NodeInfo info = node.ToNodeInfo();
// Then all fields should match
Assert.Equal(node.IsAlwaysLeaf, info.IsLeaf);
Assert.Equal(node.Label, info.Label);
Assert.Equal(node.NodeType, info.NodeType);
string[] nodePath = node.GetNodePath().Split(TreeNode.PathPartSeperator);
string[] nodeInfoPathParts = info.NodePath.Split(TreeNode.PathPartSeperator);
Assert.Equal(nodePath.Length, nodeInfoPathParts.Length);
for (int i = 0; i < nodePath.Length; i++)
{
Assert.Equal(nodePath[i], nodeInfoPathParts[i]);
}
}
[Fact]
public void AddChildShouldSetParent()
{
TreeNode parent = new TreeNode("parent");
TreeNode child = new TreeNode("child");
Assert.Null(child.Parent);
parent.AddChild(child);
Assert.Equal(parent, child.Parent);
}
[Fact]
public void GetChildrenShouldReturnReadonlyList()
{
TreeNode node = new TreeNode("parent");
IList<TreeNode> children = node.GetChildren();
Assert.Throws<NotSupportedException>(() => children.Add(new TreeNode("child")));
}
[Fact]
public void GetChildrenShouldReturnAddedNodesInOrder()
{
TreeNode parent = new TreeNode("parent");
TreeNode[] expectedKids = new TreeNode[] { new TreeNode("1"), new TreeNode("2") };
foreach (TreeNode child in expectedKids)
{
parent.AddChild(child);
}
IList<TreeNode> children = parent.GetChildren();
Assert.Equal(expectedKids.Length, children.Count);
for (int i = 0; i < expectedKids.Length; i++)
{
Assert.Equal(expectedKids[i], children[i]);
}
}
public void MultiLevelTreeShouldFormatPath()
{
TreeNode root = new TreeNode("root");
Assert.Equal("/root" , root.GetNodePath());
TreeNode level1Child1 = new TreeNode("L1C1");
TreeNode level1Child2 = new TreeNode("L1C2");
root.AddChild(level1Child1);
root.AddChild(level1Child2);
Assert.Equal("/root/L1C1" , level1Child1.GetNodePath());
Assert.Equal("/root/L1C2", level1Child2.GetNodePath());
TreeNode level2Child1 = new TreeNode("L2C2");
level1Child1.AddChild(level2Child1);
Assert.Equal("/root/L1C1/L2C2", level2Child1.GetNodePath());
}
[Fact]
public void ServerNodeContextShouldIncludeServer()
{
// given a successful Server creation
SetupAndRegisterTestConnectionService();
Server smoServer = new Server(new ServerConnection(new SqlConnection(fakeConnectionString)));
ServerNode node = SetupServerNodeWithServer(smoServer);
// When I get the context for a ServerNode
var context = node.GetContextAs<SmoQueryContext>();
// Then I expect it to contain the server I created
Assert.NotNull(context);
Assert.Equal(smoServer, context.Server);
// And the server should be the parent
Assert.Equal(smoServer, context.Parent);
Assert.Null(context.Database);
}
[Fact]
public void ServerNodeContextShouldSetErrorMessageIfSqlConnectionIsNull()
{
// given a connectionInfo with no SqlConnection to use for queries
ConnectionService connService = SetupAndRegisterTestConnectionService();
connService.OwnerToConnectionMap.Remove(defaultOwnerUri);
Server smoServer = new Server(new ServerConnection(new SqlConnection(fakeConnectionString)));
ServerNode node = SetupServerNodeWithServer(smoServer);
// When I get the context for a ServerNode
var context = node.GetContextAs<SmoQueryContext>();
// Then I expect it to be in an error state
Assert.Null(context);
Assert.Equal(
string.Format(CultureInfo.CurrentCulture, SR.ServerNodeConnectionError, defaultConnectionDetails.ServerName),
node.ErrorStateMessage);
}
[Fact]
public void ServerNodeContextShouldSetErrorMessageIfConnFailureExceptionThrown()
{
// given a connectionInfo with no SqlConnection to use for queries
SetupAndRegisterTestConnectionService();
Server smoServer = new Server(new ServerConnection(new SqlConnection(fakeConnectionString)));
string expectedMsg = "ConnFailed!";
ServerNode node = SetupServerNodeWithExceptionCreator(new ConnectionFailureException(expectedMsg));
// When I get the context for a ServerNode
var context = node.GetContextAs<SmoQueryContext>();
// Then I expect it to be in an error state
Assert.Null(context);
Assert.Equal(
string.Format(CultureInfo.CurrentCulture, SR.TreeNodeError, expectedMsg),
node.ErrorStateMessage);
}
[Fact]
public void ServerNodeContextShouldSetErrorMessageIfExceptionThrown()
{
// given a connectionInfo with no SqlConnection to use for queries
SetupAndRegisterTestConnectionService();
Server smoServer = new Server(new ServerConnection(new SqlConnection(fakeConnectionString)));
string expectedMsg = "Failed!";
ServerNode node = SetupServerNodeWithExceptionCreator(new Exception(expectedMsg));
// When I get the context for a ServerNode
var context = node.GetContextAs<SmoQueryContext>();
// Then I expect it to be in an error state
Assert.Null(context);
Assert.Equal(
string.Format(CultureInfo.CurrentCulture, SR.TreeNodeError, expectedMsg),
node.ErrorStateMessage);
}
private ConnectionService SetupAndRegisterTestConnectionService()
{
ConnectionService connService = TestObjects.GetTestConnectionService();
ConnectionInfo connectionInfo = new ConnectionInfo(TestObjects.GetTestSqlConnectionFactory(),
defaultOwnerUri, defaultConnectionDetails);
connectionInfo.AddConnection("Default", new SqlConnection());
connService.OwnerToConnectionMap.Add(defaultOwnerUri, connectionInfo);
ServiceProvider.RegisterSingleService(connService);
return connService;
}
private ServerNode SetupServerNodeWithServer(Server smoServer)
{
Mock<SmoServerCreator> creator = new Mock<SmoServerCreator>();
creator.Setup(c => c.Create(It.IsAny<SqlConnection>()))
.Returns(() => smoServer);
ServerNode node = SetupServerNodeWithCreator(creator.Object);
return node;
}
private ServerNode SetupServerNodeWithExceptionCreator(Exception ex)
{
Mock<SmoServerCreator> creator = new Mock<SmoServerCreator>();
creator.Setup(c => c.Create(It.IsAny<SqlConnection>()))
.Throws(ex);
ServerNode node = SetupServerNodeWithCreator(creator.Object);
return node;
}
private ServerNode SetupServerNodeWithCreator(SmoServerCreator creator)
{
ServerNode node = new ServerNode(defaultConnParams, ServiceProvider);
node.ServerCreator = creator;
return node;
}
[Fact]
public void ServerNodeChildrenShouldIncludeFoldersAndDatabases()
{
// Given a server with 1 database
SetupAndRegisterTestConnectionService();
ServiceProvider.RegisterSingleService(new ObjectExplorerService());
string dbName = "DB1";
Mock<NamedSmoObject> smoObjectMock = new Mock<NamedSmoObject>();
smoObjectMock.SetupGet(s => s.Name).Returns(dbName);
Mock<SqlDatabaseQuerier> querierMock = new Mock<SqlDatabaseQuerier>();
querierMock.Setup(q => q.Query(It.IsAny<SmoQueryContext>()))
.Returns(smoObjectMock.Object.SingleItemAsEnumerable());
ServiceProvider.Register<SmoQuerier>(() => new[] { querierMock.Object });
Server smoServer = new Server(new ServerConnection(new SqlConnection(fakeConnectionString)));
ServerNode node = SetupServerNodeWithServer(smoServer);
// When I populate its children
IList<TreeNode> children = node.Expand();
// Then I expect it to contain server-level folders
Assert.Equal(3, children.Count);
VerifyTreeNode<FolderNode>(children[0], "Folder", SR.SchemaHierarchy_Databases);
VerifyTreeNode<FolderNode>(children[1], "Folder", SR.SchemaHierarchy_Security);
VerifyTreeNode<FolderNode>(children[2], "Folder", SR.SchemaHierarchy_ServerObjects);
// And the database is contained under it
TreeNode databases = children[0];
IList<TreeNode> dbChildren = databases.Expand();
Assert.Equal(2, dbChildren.Count);
Assert.Equal(SR.SchemaHierarchy_SystemDatabases, dbChildren[0].NodeValue);
TreeNode dbNode = dbChildren[1];
Assert.Equal(dbName, dbNode.NodeValue);
Assert.Equal(dbName, dbNode.Label);
Assert.False(dbNode.IsAlwaysLeaf);
// Note: would like to verify Database in the context, but cannot since it's a Sealed class and isn't easily mockable
}
private void VerifyTreeNode<T>(TreeNode node, string nodeType, string folderValue)
where T : TreeNode
{
T nodeAsT = node as T;
Assert.NotNull(nodeAsT);
Assert.Equal(nodeType, nodeAsT.NodeType);
Assert.Equal(folderValue, nodeAsT.NodeValue);
}
}
}
//
// 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.Collections.Generic;
using System.Data.SqlClient;
using System.Globalization;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.Extensibility;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel;
using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility;
using Moq;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
{
/// <summary>
/// Tests covering basic operation of Node based classes
/// </summary>
public class NodeTests : ObjectExplorerTestBase
{
private string defaultOwnerUri = "objectexplorer://myserver";
private ServerInfo defaultServerInfo;
private ConnectionDetails defaultConnectionDetails;
private ConnectionCompleteParams defaultConnParams;
private string fakeConnectionString = "Data Source=server;Initial Catalog=database;Integrated Security=False;User Id=user";
public NodeTests()
{
defaultServerInfo = TestObjects.GetTestServerInfo();
defaultConnectionDetails = new ConnectionDetails()
{
DatabaseName = "master",
ServerName = "localhost",
UserName = "serverAdmin",
Password = "..."
};
defaultConnParams = new ConnectionCompleteParams()
{
ServerInfo = defaultServerInfo,
ConnectionSummary = defaultConnectionDetails,
OwnerUri = defaultOwnerUri
};
// TODO can all tests use the standard service provider?
ServiceProvider = ExtensionServiceProvider.CreateDefaultServiceProvider();
}
[Fact]
public void ServerNodeConstructorValidatesFields()
{
Assert.Throws<ArgumentNullException>(() => new ServerNode(null, ServiceProvider));
Assert.Throws<ArgumentNullException>(() => new ServerNode(defaultConnParams, null));
}
[Fact]
public void ServerNodeConstructorShouldSetValuesCorrectly()
{
// Given a server node with valid inputs
ServerNode node = new ServerNode(defaultConnParams, ServiceProvider);
// Then expect all fields set correctly
Assert.False(node.IsAlwaysLeaf, "Server node should never be a leaf");
Assert.Equal(defaultConnectionDetails.ServerName, node.NodeValue);
string expectedLabel = defaultConnectionDetails.ServerName + " (SQL Server " + defaultServerInfo.ServerVersion + " - "
+ defaultConnectionDetails.UserName + ")";
Assert.Equal(expectedLabel, node.Label);
Assert.Equal(NodeTypes.Server.ToString(), node.NodeType);
string[] nodePath = node.GetNodePath().Split(TreeNode.PathPartSeperator);
Assert.Equal(1, nodePath.Length);
Assert.Equal(defaultConnectionDetails.ServerName, nodePath[0]);
}
[Fact]
public void ServerNodeLabelShouldIgnoreUserNameIfEmptyOrNull()
{
// Given no username set
ConnectionSummary integratedAuthSummary = new ConnectionSummary()
{
DatabaseName = defaultConnectionDetails.DatabaseName,
ServerName = defaultConnectionDetails.ServerName,
UserName = null
};
ConnectionCompleteParams connParams = new ConnectionCompleteParams()
{
ConnectionSummary = integratedAuthSummary,
ServerInfo = defaultServerInfo,
OwnerUri = defaultOwnerUri
};
// When querying label
string label = new ServerNode(connParams, ServiceProvider).Label;
// Then only server name and version shown
string expectedLabel = defaultConnectionDetails.ServerName + " (SQL Server " + defaultServerInfo.ServerVersion + ")";
Assert.Equal(expectedLabel, label);
}
[Fact]
public void ServerNodeConstructorShouldShowDbNameForCloud()
{
defaultServerInfo.IsCloud = true;
// Given a server node for a cloud DB, with master name
ServerNode node = new ServerNode(defaultConnParams, ServiceProvider);
// Then expect label to not include db name
string expectedLabel = defaultConnectionDetails.ServerName + " (SQL Server " + defaultServerInfo.ServerVersion + " - "
+ defaultConnectionDetails.UserName + ")";
Assert.Equal(expectedLabel, node.Label);
// But given a server node for a cloud DB that's not master
defaultConnectionDetails.DatabaseName = "NotMaster";
node = new ServerNode(defaultConnParams, ServiceProvider);
// Then expect label to include db name
expectedLabel = defaultConnectionDetails.ServerName + " (SQL Server " + defaultServerInfo.ServerVersion + " - "
+ defaultConnectionDetails.UserName + ", " + defaultConnectionDetails.DatabaseName + ")";
Assert.Equal(expectedLabel, node.Label);
}
[Fact]
public void ToNodeInfoIncludeAllFields()
{
// Given a server connection
ServerNode node = new ServerNode(defaultConnParams, ServiceProvider);
// When converting to NodeInfo
NodeInfo info = node.ToNodeInfo();
// Then all fields should match
Assert.Equal(node.IsAlwaysLeaf, info.IsLeaf);
Assert.Equal(node.Label, info.Label);
Assert.Equal(node.NodeType, info.NodeType);
string[] nodePath = node.GetNodePath().Split(TreeNode.PathPartSeperator);
string[] nodeInfoPathParts = info.NodePath.Split(TreeNode.PathPartSeperator);
Assert.Equal(nodePath.Length, nodeInfoPathParts.Length);
for (int i = 0; i < nodePath.Length; i++)
{
Assert.Equal(nodePath[i], nodeInfoPathParts[i]);
}
}
[Fact]
public void AddChildShouldSetParent()
{
TreeNode parent = new TreeNode("parent");
TreeNode child = new TreeNode("child");
Assert.Null(child.Parent);
parent.AddChild(child);
Assert.Equal(parent, child.Parent);
}
[Fact]
public void GetChildrenShouldReturnReadonlyList()
{
TreeNode node = new TreeNode("parent");
IList<TreeNode> children = node.GetChildren();
Assert.Throws<NotSupportedException>(() => children.Add(new TreeNode("child")));
}
[Fact]
public void GetChildrenShouldReturnAddedNodesInOrder()
{
TreeNode parent = new TreeNode("parent");
TreeNode[] expectedKids = new TreeNode[] { new TreeNode("1"), new TreeNode("2") };
foreach (TreeNode child in expectedKids)
{
parent.AddChild(child);
}
IList<TreeNode> children = parent.GetChildren();
Assert.Equal(expectedKids.Length, children.Count);
for (int i = 0; i < expectedKids.Length; i++)
{
Assert.Equal(expectedKids[i], children[i]);
}
}
public void MultiLevelTreeShouldFormatPath()
{
TreeNode root = new TreeNode("root");
Assert.Equal("/root" , root.GetNodePath());
TreeNode level1Child1 = new TreeNode("L1C1");
TreeNode level1Child2 = new TreeNode("L1C2");
root.AddChild(level1Child1);
root.AddChild(level1Child2);
Assert.Equal("/root/L1C1" , level1Child1.GetNodePath());
Assert.Equal("/root/L1C2", level1Child2.GetNodePath());
TreeNode level2Child1 = new TreeNode("L2C2");
level1Child1.AddChild(level2Child1);
Assert.Equal("/root/L1C1/L2C2", level2Child1.GetNodePath());
}
[Fact]
public void ServerNodeContextShouldIncludeServer()
{
// given a successful Server creation
SetupAndRegisterTestConnectionService();
Server smoServer = new Server(new ServerConnection(new SqlConnection(fakeConnectionString)));
ServerNode node = SetupServerNodeWithServer(smoServer);
// When I get the context for a ServerNode
var context = node.GetContextAs<SmoQueryContext>();
// Then I expect it to contain the server I created
Assert.NotNull(context);
Assert.Equal(smoServer, context.Server);
// And the server should be the parent
Assert.Equal(smoServer, context.Parent);
Assert.Null(context.Database);
}
[Fact]
public void ServerNodeContextShouldSetErrorMessageIfSqlConnectionIsNull()
{
// given a connectionInfo with no SqlConnection to use for queries
ConnectionService connService = SetupAndRegisterTestConnectionService();
connService.OwnerToConnectionMap.Remove(defaultOwnerUri);
Server smoServer = new Server(new ServerConnection(new SqlConnection(fakeConnectionString)));
ServerNode node = SetupServerNodeWithServer(smoServer);
// When I get the context for a ServerNode
var context = node.GetContextAs<SmoQueryContext>();
// Then I expect it to be in an error state
Assert.Null(context);
Assert.Equal(
string.Format(CultureInfo.CurrentCulture, SR.ServerNodeConnectionError, defaultConnectionDetails.ServerName),
node.ErrorStateMessage);
}
[Fact]
public void ServerNodeContextShouldSetErrorMessageIfConnFailureExceptionThrown()
{
// given a connectionInfo with no SqlConnection to use for queries
SetupAndRegisterTestConnectionService();
Server smoServer = new Server(new ServerConnection(new SqlConnection(fakeConnectionString)));
string expectedMsg = "ConnFailed!";
ServerNode node = SetupServerNodeWithExceptionCreator(new ConnectionFailureException(expectedMsg));
// When I get the context for a ServerNode
var context = node.GetContextAs<SmoQueryContext>();
// Then I expect it to be in an error state
Assert.Null(context);
Assert.Equal(
string.Format(CultureInfo.CurrentCulture, SR.TreeNodeError, expectedMsg),
node.ErrorStateMessage);
}
[Fact]
public void ServerNodeContextShouldSetErrorMessageIfExceptionThrown()
{
// given a connectionInfo with no SqlConnection to use for queries
SetupAndRegisterTestConnectionService();
Server smoServer = new Server(new ServerConnection(new SqlConnection(fakeConnectionString)));
string expectedMsg = "Failed!";
ServerNode node = SetupServerNodeWithExceptionCreator(new Exception(expectedMsg));
// When I get the context for a ServerNode
var context = node.GetContextAs<SmoQueryContext>();
// Then I expect it to be in an error state
Assert.Null(context);
Assert.Equal(
string.Format(CultureInfo.CurrentCulture, SR.TreeNodeError, expectedMsg),
node.ErrorStateMessage);
}
private ConnectionService SetupAndRegisterTestConnectionService()
{
ConnectionService connService = TestObjects.GetTestConnectionService();
ConnectionInfo connectionInfo = new ConnectionInfo(TestObjects.GetTestSqlConnectionFactory(),
defaultOwnerUri, defaultConnectionDetails);
connectionInfo.AddConnection("Default", new SqlConnection());
connService.OwnerToConnectionMap.Add(defaultOwnerUri, connectionInfo);
ServiceProvider.RegisterSingleService(connService);
return connService;
}
private ServerNode SetupServerNodeWithServer(Server smoServer)
{
Mock<SmoServerCreator> creator = new Mock<SmoServerCreator>();
creator.Setup(c => c.Create(It.IsAny<SqlConnection>()))
.Returns(() => smoServer);
ServerNode node = SetupServerNodeWithCreator(creator.Object);
return node;
}
private ServerNode SetupServerNodeWithExceptionCreator(Exception ex)
{
Mock<SmoServerCreator> creator = new Mock<SmoServerCreator>();
creator.Setup(c => c.Create(It.IsAny<SqlConnection>()))
.Throws(ex);
ServerNode node = SetupServerNodeWithCreator(creator.Object);
return node;
}
private ServerNode SetupServerNodeWithCreator(SmoServerCreator creator)
{
ServerNode node = new ServerNode(defaultConnParams, ServiceProvider);
node.ServerCreator = creator;
return node;
}
[Fact]
public void ServerNodeChildrenShouldIncludeFoldersAndDatabases()
{
// Given a server with 1 database
SetupAndRegisterTestConnectionService();
ServiceProvider.RegisterSingleService(new ObjectExplorerService());
string dbName = "DB1";
Mock<NamedSmoObject> smoObjectMock = new Mock<NamedSmoObject>();
smoObjectMock.SetupGet(s => s.Name).Returns(dbName);
Mock<SqlDatabaseQuerier> querierMock = new Mock<SqlDatabaseQuerier>();
querierMock.Setup(q => q.Query(It.IsAny<SmoQueryContext>(), ""))
.Returns(smoObjectMock.Object.SingleItemAsEnumerable());
ServiceProvider.Register<SmoQuerier>(() => new[] { querierMock.Object });
Server smoServer = new Server(new ServerConnection(new SqlConnection(fakeConnectionString)));
ServerNode node = SetupServerNodeWithServer(smoServer);
// When I populate its children
IList<TreeNode> children = node.Expand();
// Then I expect it to contain server-level folders
Assert.Equal(3, children.Count);
VerifyTreeNode<FolderNode>(children[0], "Folder", SR.SchemaHierarchy_Databases);
VerifyTreeNode<FolderNode>(children[1], "Folder", SR.SchemaHierarchy_Security);
VerifyTreeNode<FolderNode>(children[2], "Folder", SR.SchemaHierarchy_ServerObjects);
// And the database is contained under it
TreeNode databases = children[0];
IList<TreeNode> dbChildren = databases.Expand();
Assert.Equal(2, dbChildren.Count);
Assert.Equal(SR.SchemaHierarchy_SystemDatabases, dbChildren[0].NodeValue);
TreeNode dbNode = dbChildren[1];
Assert.Equal(dbName, dbNode.NodeValue);
Assert.Equal(dbName, dbNode.Label);
Assert.False(dbNode.IsAlwaysLeaf);
// Note: would like to verify Database in the context, but cannot since it's a Sealed class and isn't easily mockable
}
private void VerifyTreeNode<T>(TreeNode node, string nodeType, string folderValue)
where T : TreeNode
{
T nodeAsT = node as T;
Assert.NotNull(nodeAsT);
Assert.Equal(nodeType, nodeAsT.NodeType);
Assert.Equal(folderValue, nodeAsT.NodeValue);
}
}
}