1244 lines
58 KiB
C#
Raw Normal View History

// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace EntityFramework.PowerShell.UnitTests
{
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Xml.Linq;
using EnvDTE;
using System.Data.Entity.TestHelpers;
using Microsoft.Win32;
using Moq;
using Xunit;
public class ConnectionFactoryConfigTests : TestBase
{
#region Well-known values
// Hard-coding this rather than getting it dynamically because the product code gets it dynamically
// and the tests need to make sure it gets the correct thing. This will need to be updated when the
// assembly version number is incremented.
private static readonly Version _builtEntityFrameworkVersion = new Version("6.0.0.0");
private static readonly Version _net45EntityFrameworkVersion = new Version("6.0.0.0");
private static readonly Version _net40EntityFrameworkVersion = new Version("6.0.0.0");
private const string EntityFrameworkSectionFormat =
"System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version={0}, Culture=neutral, PublicKeyToken=b77a5c561934e089";
private static readonly string _net45EntityFrameworkSectionName = string.Format(
CultureInfo.InvariantCulture, EntityFrameworkSectionFormat, _net45EntityFrameworkVersion);
private static readonly string _net40EntityFrameworkSectionName = string.Format(
CultureInfo.InvariantCulture, EntityFrameworkSectionFormat, _net40EntityFrameworkVersion);
#endregion
#region Updating entityFramework section and adding defaultConnectionFactory
[Fact]
public void ConfigFileProcessor_calls_both_AddConnectionFactoryToConfig_and_AddOrUpdateConfigSection_even_if_both_return_true()
{
// Test ensures code does not skip calling one method if the other returns true through the use of
// short-circuit evaluation.
RunTestWithTempFilename(
tempFileName =>
{
var mockManipulator = new Mock<System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator>();
mockManipulator
.Setup(
m =>
m.AddConnectionFactoryToConfig(
It.IsAny<XDocument>(),
It.IsAny<System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification>())).
Returns(true);
mockManipulator
.Setup(m => m.AddOrUpdateConfigSection(It.IsAny<XDocument>(), It.IsAny<Version>())).
Returns(true);
new XDocument(new XElement("fake")).Save(tempFileName);
var mockedItem = new Mock<ProjectItem>();
mockedItem.Setup(p => p.get_FileNames(0)).Returns(tempFileName);
new System.Data.Entity.ConnectionFactoryConfig.ConfigFileProcessor()
.ProcessConfigFile(
mockedItem.Object, new Func<XDocument, bool>[]
{
c =>
mockManipulator.Object.AddOrUpdateConfigSection(c, _net45EntityFrameworkVersion),
c =>
mockManipulator.Object.AddConnectionFactoryToConfig(
c,
new System.Data.Entity.ConnectionFactoryConfig.
ConnectionFactorySpecification("F"))
});
mockManipulator.Verify(
m =>
m.AddConnectionFactoryToConfig(
It.IsAny<XDocument>(),
It.IsAny<System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification>()));
mockManipulator.Verify(m => m.AddOrUpdateConfigSection(It.IsAny<XDocument>(), _net45EntityFrameworkVersion));
});
}
[Fact]
public void AddSqlCompactConnectionFactoryToConfig_does_nothing_if_correct_SQL_Compact_entry_already_exists()
{
var config = CreateConnectionFactoryConfigDoc(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName);
var factoryAdded = new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator()
.AddOrUpdateConnectionFactoryInConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName));
Assert.False(factoryAdded);
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
GetFactoryName(config));
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName,
GetArgument(config));
}
[Fact]
public void AddSqlCompactConnectionFactoryToConfig_adds_factory_if_no_factory_name_already_exists()
{
var config = CreateConnectionFactoryConfigDoc(null);
var factoryAdded = new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator()
.AddOrUpdateConnectionFactoryInConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName));
Assert.True(factoryAdded);
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
GetFactoryName(config));
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName,
GetArgument(config));
}
[Fact]
public void AddSqlCompactConnectionFactoryToConfig_adds_factory_if_entityFramework_element_is_missing()
{
var config =
new XDocument(
new XElement(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName));
var factoryAdded = new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator()
.AddOrUpdateConnectionFactoryInConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName));
Assert.True(factoryAdded);
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
GetFactoryName(config));
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName,
GetArgument(config));
}
[Fact]
public void AddSqlCompactConnectionFactoryToConfig_adds_factory_if_configuration_element_is_missing()
{
var config = new XDocument();
var factoryAdded = new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator()
.AddOrUpdateConnectionFactoryInConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName));
Assert.True(factoryAdded);
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
GetFactoryName(config));
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName,
GetArgument(config));
}
[Fact]
public void AddSqlCompactConnectionFactoryToConfig_sets_factory_to_SQL_Compact_even_if_entry_already_exists()
{
var config = CreateConnectionFactoryConfigDoc("SomeConnectionFactory");
var factoryAdded = new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator()
.AddOrUpdateConnectionFactoryInConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName));
Assert.True(factoryAdded);
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
GetFactoryName(config));
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName,
GetArgument(config));
}
[Fact]
public void AddSqlCompactConnectionFactoryToConfig_sets_factory_to_SQL_Compact_even_if_entry_with_param_already_exists()
{
var config =
CreateConnectionFactoryConfigDoc(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlConnectionFactoryName,
"Database=Bob");
var factoryAdded = new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator()
.AddOrUpdateConnectionFactoryInConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName));
Assert.True(factoryAdded);
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCeConnectionFactoryName,
GetFactoryName(config));
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlCompactProviderName,
GetArgument(config));
}
[Fact]
public void AddConnectionFactoryToConfig_does_nothing_if_factory_name_already_exists()
{
var config = CreateConnectionFactoryConfigDoc("SomeConnectionFactory");
var factoryAdded = new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().
AddConnectionFactoryToConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification(
"NewConnectionFactory", "NewBaseConnectionString"));
Assert.False(factoryAdded);
Assert.Equal("SomeConnectionFactory", GetFactoryName(config));
}
[Fact]
public void AddConnectionFactoryToConfig_adds_factory_if_no_factory_name_already_exists()
{
var config = CreateConnectionFactoryConfigDoc(null);
var factoryAdded = new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().
AddConnectionFactoryToConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification(
"NewConnectionFactory", "NewBaseConnectionString"));
Assert.True(factoryAdded);
Assert.Equal("NewConnectionFactory", GetFactoryName(config));
Assert.Equal("NewBaseConnectionString", GetArgument(config));
}
[Fact]
public void AddConnectionFactoryToConfig_adds_factory_if_entityFramework_element_is_missing()
{
var config =
new XDocument(
new XElement(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName));
var factoryAdded = new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().
AddConnectionFactoryToConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification(
"NewConnectionFactory", "NewBaseConnectionString"));
Assert.True(factoryAdded);
Assert.Equal("NewConnectionFactory", GetFactoryName(config));
Assert.Equal("NewBaseConnectionString", GetArgument(config));
}
[Fact]
public void AddConnectionFactoryToConfig_adds_factory_if_configuration_element_is_missing()
{
var config = new XDocument();
var factoryAdded = new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().
AddConnectionFactoryToConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification(
"NewConnectionFactory", "NewBaseConnectionString"));
Assert.True(factoryAdded);
Assert.Equal("NewConnectionFactory", GetFactoryName(config));
Assert.Equal("NewBaseConnectionString", GetArgument(config));
}
[Fact]
public void AddConnectionFactoryToConfig_adds_factory_with_no_parameters()
{
var config = new XDocument();
var factoryAdded = new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().
AddConnectionFactoryToConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification("NewConnectionFactory"));
Assert.True(factoryAdded);
Assert.Equal("NewConnectionFactory", GetFactoryName(config));
Assert.Null(
config.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName)
.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.EntityFrameworkElementName)
.Element(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.DefaultConnectionFactoryElementName)
.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ParametersElementName));
}
[Fact]
public void AddConnectionFactoryToConfig_adds_factory_with_many_parameters()
{
var config = new XDocument();
var factoryAdded = new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().
AddConnectionFactoryToConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification(
"NewConnectionFactory", "1", "2", "3"));
Assert.True(factoryAdded);
Assert.Equal("NewConnectionFactory", GetFactoryName(config));
Assert.Equal("1", GetArguments(config).First());
Assert.Equal("2", GetArguments(config).Skip(1).First());
Assert.Equal("3", GetArguments(config).Skip(2).First());
}
private XDocument CreateConnectionFactoryConfigDoc(string factoryName)
{
return new XDocument(
new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName,
new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.EntityFrameworkElementName,
factoryName != null
? new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.
DefaultConnectionFactoryElementName, new XAttribute("type", factoryName))
: null)));
}
private XDocument CreateConnectionFactoryConfigDoc(string factoryName, string param)
{
return new XDocument(
new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName,
new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.EntityFrameworkElementName,
new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.DefaultConnectionFactoryElementName,
new XAttribute("type", factoryName),
new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ParametersElementName,
new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ParameterElementName,
new XAttribute("value", param)))))));
}
private string GetFactoryName(XDocument config)
{
return config.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName)
.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.EntityFrameworkElementName)
.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.DefaultConnectionFactoryElementName)
.Attribute("type")
.Value;
}
private string GetArgument(XDocument config)
{
return GetArguments(config).Single();
}
private IEnumerable<string> GetArguments(XDocument config)
{
return config.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName)
.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.EntityFrameworkElementName)
.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.DefaultConnectionFactoryElementName)
.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ParametersElementName)
.Elements(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ParameterElementName)
.Select(e => e.Attribute("value").Value);
}
[Fact]
public void AddOrUpdateConfigSection_does_nothing_if_EF_assembly_name_is_up_to_date()
{
var config = CreateConfigSectionDoc(_net45EntityFrameworkSectionName, addRequirePermission: true);
var sectionModified =
new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().AddOrUpdateConfigSection(
config, _net45EntityFrameworkVersion);
Assert.False(sectionModified);
Assert.Equal(_net45EntityFrameworkSectionName, GetEfSectionName(config));
}
[Fact]
public void AddOrUpdateConfigSection_adds_EF_section_if_configuration_element_is_missing()
{
var config = new XDocument();
var sectionModified =
new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().AddOrUpdateConfigSection(
config, _net45EntityFrameworkVersion);
Assert.True(sectionModified);
Assert.Equal(_net45EntityFrameworkSectionName, GetEfSectionName(config));
}
[Fact]
public void AddOrUpdateConfigSection_adds_EF_section_if_configSections_element_is_missing()
{
var config =
new XDocument(
new XElement(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName));
var sectionModified =
new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().AddOrUpdateConfigSection(
config, _net45EntityFrameworkVersion);
Assert.True(sectionModified);
Assert.Equal(_net45EntityFrameworkSectionName, GetEfSectionName(config));
}
[Fact]
public void AddOrUpdateConfigSection_adds_EF_section_if_configSections_element_contains_no_entries()
{
var config =
new XDocument(
new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName,
new XElement(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigSectionsElementName)));
var sectionModified =
new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().AddOrUpdateConfigSection(
config, _net45EntityFrameworkVersion);
Assert.True(sectionModified);
Assert.Equal(_net45EntityFrameworkSectionName, GetEfSectionName(config));
}
[Fact]
public void AddOrUpdateConfigSection_adds_EF_section_if_configSections_element_has_no_entityFramework_entry()
{
var config = CreateConfigSectionDoc(assemblyName: null);
var sectionModified =
new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().AddOrUpdateConfigSection(
config, _net45EntityFrameworkVersion);
Assert.True(sectionModified);
Assert.Equal(_net45EntityFrameworkSectionName, GetEfSectionName(config));
}
[Fact]
public void AddOrUpdateConfigSection_updates_EF_section_if_configSections_element_is_out_of_date()
{
var config = CreateConfigSectionDoc(_net40EntityFrameworkSectionName);
var sectionModified =
new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().AddOrUpdateConfigSection(
config, _net45EntityFrameworkVersion);
Assert.True(sectionModified);
Assert.Equal(_net45EntityFrameworkSectionName, GetEfSectionName(config));
}
[Fact]
public void AddOrUpdateConfigSection_when_using_NET4_EF_assembly_does_nothing_if_EF_assembly_name_is_up_to_date()
{
var config = CreateConfigSectionDoc(_net40EntityFrameworkSectionName, addRequirePermission: true);
var sectionModified =
new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().AddOrUpdateConfigSection(
config, _net40EntityFrameworkVersion);
Assert.False(sectionModified);
Assert.Equal(_net40EntityFrameworkSectionName, GetEfSectionName(config));
}
[Fact]
public void AddOrUpdateConfigSection_when_using_NET4_EF_assembly_updates_EF_section_if_configSections_element_is_too_new()
{
var config = CreateConfigSectionDoc(_net45EntityFrameworkSectionName);
var sectionModified =
new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().AddOrUpdateConfigSection(
config, _net40EntityFrameworkVersion);
Assert.True(sectionModified);
Assert.Equal(_net40EntityFrameworkSectionName, GetEfSectionName(config));
}
[Fact]
public void AddOrUpdateConfigSection_on_add_yields_result_that_can_load_in_partial_trust()
{
AddOrUpdateConfigSection_result_can_load_in_partial_trust(
new XDocument(
new XElement(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName)));
}
[Fact]
public void AddOrUpdateConfigSection_on_update_yields_result_that_can_load_in_partial_trust()
{
AddOrUpdateConfigSection_result_can_load_in_partial_trust(
CreateConfigSectionDoc(_net40EntityFrameworkSectionName));
}
private void AddOrUpdateConfigSection_result_can_load_in_partial_trust(XDocument config)
{
new System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator().AddOrUpdateConfigSection(
config, _net45EntityFrameworkVersion);
config.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName).Add(
new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.EntityFrameworkElementName,
new XAttribute("codeConfigurationType", typeof(FunctionalTestsConfiguration).AssemblyQualifiedName)));
var configurationFile = Path.Combine(Environment.CurrentDirectory, "Temp.config");
config.Save(configurationFile);
try
{
using (var sandbox = new PartialTrustSandbox(configurationFile: configurationFile))
{
sandbox.CreateInstance<ConnectionFactoryConfigTests>()
.LoadConfiguration();
}
}
finally
{
File.Delete(configurationFile);
}
}
private void LoadConfiguration()
{
new PartialTrustContext();
}
private class PartialTrustContext : DbContext
{
}
private XDocument CreateConfigSectionDoc(string assemblyName, bool addRequirePermission = false)
{
var dummyElement = new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.SectionElementName,
new XAttribute("name", "SamVimes"),
new XAttribute("type", "Treacle Mine Road"));
XElement sectionElement;
if (assemblyName == null)
{
sectionElement = dummyElement;
}
else
{
sectionElement = new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.SectionElementName,
new XAttribute(
"name", System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.EntityFrameworkElementName),
new XAttribute("type", assemblyName));
if (addRequirePermission)
{
sectionElement.Add(new XAttribute("requirePermission", false));
}
}
return new XDocument(
new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName,
new XElement(
System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigSectionsElementName,
dummyElement,
sectionElement)));
}
private string GetEfSectionName(XDocument config)
{
return config.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigurationElementName)
.Element(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.ConfigSectionsElementName)
.Elements(System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.SectionElementName)
.Where(
e =>
e.Attributes("name").Any(
a =>
a.Value == System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator.EntityFrameworkElementName))
.Select(e => e.Attribute("type").Value)
.Single();
}
#endregion
#region Config file processing tests
[Fact]
public void ConfigFileFinder_finds_items_named_app_config_and_web_config_in_Visual_Studio_ProjectItems()
{
var items = new List<ProjectItem>();
new System.Data.Entity.ConnectionFactoryConfig.ConfigFileFinder()
.FindConfigFiles(
CreateMockedItems("app.config", "App.config", "Foo.config", "web.config", "Web.config", "Bar"),
i => items.Add(i));
Assert.Equal(4, items.Count);
Assert.True(items.Any(i => i.Name == "app.config"));
Assert.True(items.Any(i => i.Name == "App.config"));
Assert.True(items.Any(i => i.Name == "web.config"));
Assert.True(items.Any(i => i.Name == "Web.config"));
}
private ProjectItems CreateMockedItems(params string[] itemNames)
{
var items = new List<ProjectItem>();
foreach (var name in itemNames)
{
var mockedItem = new Mock<ProjectItem>();
mockedItem.Setup(p => p.Name).Returns(name);
items.Add(mockedItem.Object);
}
var mockedProjectItems = new Mock<ProjectItems>();
mockedProjectItems.Setup(p => p.GetEnumerator()).Returns(items.GetEnumerator());
return mockedProjectItems.Object;
}
[Fact]
public void ConfigFileProcessor_saves_config_file_if_config_document_is_modified()
{
ConfigFileSaveTest(shouldSave: true);
}
[Fact]
public void ConfigFileProcessor_does_not_save_config_file_if_config_document_is_not_modified()
{
ConfigFileSaveTest(shouldSave: false);
}
[Fact]
public void If_config_file_cannot_be_saved_when_it_needs_to_be_then_an_exception_is_thrown()
{
ConfigFileSaveTest(shouldSave: true, writeProtectFile: true);
}
private void RunTestWithTempFilename(Action<string> test)
{
var tempFileName = Path.GetTempFileName();
try
{
test(tempFileName);
}
finally
{
try
{
File.SetAttributes(tempFileName, File.GetAttributes(tempFileName) & ~FileAttributes.ReadOnly);
File.Delete(tempFileName);
}
catch (FileNotFoundException)
{
}
}
}
private void ConfigFileSaveTest(bool shouldSave, bool writeProtectFile = false)
{
RunTestWithTempFilename(
tempFileName =>
{
new XDocument(new XElement("fake")).Save(tempFileName);
if (writeProtectFile)
{
File.SetAttributes(tempFileName, File.GetAttributes(tempFileName) | FileAttributes.ReadOnly);
}
var mockedItem = new Mock<ProjectItem>();
mockedItem.Setup(p => p.get_FileNames(0)).Returns(tempFileName);
var mockedManipulator = new Mock<System.Data.Entity.ConnectionFactoryConfig.ConfigFileManipulator>();
mockedManipulator
.Setup(
m =>
m.AddConnectionFactoryToConfig(
It.IsAny<XDocument>(),
It.IsAny<System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification>()))
.Callback(
(XDocument config, System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification _)
=> config.Element("fake").Add(new XElement("modified")))
.Returns(shouldSave);
Assert.ThrowsDelegate test =
() => new System.Data.Entity.ConnectionFactoryConfig.ConfigFileProcessor()
.ProcessConfigFile(
mockedItem.Object,
new Func<XDocument, bool>[]
{
c => mockedManipulator.Object.AddOrUpdateConfigSection(c, _net45EntityFrameworkVersion),
c =>
mockedManipulator.Object.AddConnectionFactoryToConfig(
c,
new System.Data.Entity.ConnectionFactoryConfig.
ConnectionFactorySpecification("F"))
});
if (shouldSave && writeProtectFile)
{
Assert.Equal(
System.Data.Entity.Migrations.Resources.Strings.SaveConnectionFactoryInConfigFailed(
tempFileName), Assert.Throws<IOException>(test).Message);
}
else
{
test();
}
var doc = XDocument.Load(tempFileName);
Assert.Equal(shouldSave && !writeProtectFile, doc.Element("fake").Elements("modified").Any());
});
}
#endregion
#region SQL Server detection tests
[Fact]
public void SqlServerDetector_detects_SQL_Express_when_service_is_running()
{
Assert.True(
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
new Mock<System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy>().Object,
CreateMockedController()).IsSqlExpressInstalled());
}
[Fact]
public void SqlServerDetector_detects_no_SQL_Express_when_service_is_present_but_not_running()
{
Assert.False(
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
new Mock<System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy>().Object,
CreateMockedController(ServiceControllerStatus.Stopped)).IsSqlExpressInstalled());
}
[Fact]
public void SqlServerDetector_detects_no_SQL_Express_when_service_is_not_found()
{
Assert.False(
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
new Mock<System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy>().Object,
CreateMockedController(status: null)).IsSqlExpressInstalled());
}
private System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy CreateMockedController(
ServiceControllerStatus? status = ServiceControllerStatus.Running)
{
var mockController = new Mock<System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy>();
if (status != null)
{
mockController.Setup(m => m.Status).Returns(status.Value);
}
else
{
mockController.Setup(m => m.Status).Throws(new InvalidOperationException());
}
return mockController.Object;
}
[Fact]
public void SqlServerDetector_detects_the_version_of_LocalDB_in_the_registry_when_only_one_version_is_installed()
{
Assert.Equal(
"some version",
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
CreatedMockedRegistryKey("some version"),
new Mock<System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy>().Object)
.TryGetLocalDBVersionInstalled());
}
[Fact]
public void SqlServerDetector_detects_the_highest_orderable_version_of_LocalDB_in_the_registry_when_multiple_versions_are_installed(
)
{
Assert.Equal(
"12.0",
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
CreatedMockedRegistryKey("11.0", "12.0", "11.5"),
new Mock<System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy>().Object)
.TryGetLocalDBVersionInstalled());
}
[Fact]
public void SqlServerDetector_orders_LocalDB_versions_numerically_when_multiple_versions_are_installed()
{
Assert.Equal(
"100",
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
CreatedMockedRegistryKey("20", "100"),
new Mock<System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy>().Object)
.TryGetLocalDBVersionInstalled());
}
[Fact]
public void SqlServerDetector_ignores_LocalDB_versions_that_are_not_numeric_when_multiple_versions_are_installed()
{
Assert.Equal(
"12.0",
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
CreatedMockedRegistryKey("11.0", "12.0", "dingo", "11.5"),
new Mock<System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy>().Object)
.TryGetLocalDBVersionInstalled());
}
[Fact]
public void SqlServerDetector_returns_null_if_multiple_non_numeric_LocalDB_versions_are_installed()
{
Assert.Null(
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
CreatedMockedRegistryKey("kangaroo", "dingo", "wallaby"),
new Mock<System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy>().Object)
.TryGetLocalDBVersionInstalled());
}
[Fact]
public void SqlServerDetector_returns_null_if_LocalDB_registry_exists_but_no_version_keys_are_found()
{
Assert.Null(
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
CreatedMockedRegistryKey(new string[0]),
new Mock<System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy>().Object)
.TryGetLocalDBVersionInstalled());
}
private System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy CreatedMockedRegistryKey(params string[] versions)
{
var mockedRegistryKey = new Mock<System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy>();
mockedRegistryKey.Setup(k => k.OpenSubKey("SOFTWARE")).Returns(mockedRegistryKey.Object);
mockedRegistryKey.Setup(k => k.OpenSubKey("Microsoft")).Returns(mockedRegistryKey.Object);
mockedRegistryKey.Setup(k => k.OpenSubKey("Microsoft SQL Server Local DB")).Returns(mockedRegistryKey.Object);
mockedRegistryKey.Setup(k => k.OpenSubKey("Installed Versions")).Returns(mockedRegistryKey.Object);
mockedRegistryKey.Setup(k => k.SubKeyCount).Returns(versions.Length);
mockedRegistryKey.Setup(k => k.GetSubKeyNames()).Returns(versions);
mockedRegistryKey.Setup(k => k.OpenSubKey("Wow6432Node")).Returns(
new System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy(null));
return mockedRegistryKey.Object;
}
[Fact]
public void SqlServerDetector_returns_null_if_LocalDB_registry_keys_do_not_exist()
{
var mockedRegistryKey = new Mock<System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy>();
mockedRegistryKey.Setup(k => k.OpenSubKey("SOFTWARE")).Returns(mockedRegistryKey.Object);
mockedRegistryKey.Setup(k => k.OpenSubKey("Microsoft")).Returns(mockedRegistryKey.Object);
mockedRegistryKey.Setup(k => k.OpenSubKey("Microsoft SQL Server Local DB")).Returns(
new System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy(null));
mockedRegistryKey.Setup(k => k.OpenSubKey("Wow6432Node")).Returns(
new System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy(null));
Assert.Null(
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
mockedRegistryKey.Object,
new Mock<System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy>().Object)
.TryGetLocalDBVersionInstalled());
}
[Fact]
public void SqlServerDetector_detects_LocalDB_installation_in_Wow6432Node_if_not_found_in_normal_hive()
{
var mockedRegistryKey = new Mock<System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy>();
mockedRegistryKey.Setup(k => k.OpenSubKey("SOFTWARE")).Returns(mockedRegistryKey.Object);
mockedRegistryKey.Setup(k => k.OpenSubKey("Microsoft")).Returns(mockedRegistryKey.Object);
mockedRegistryKey.Setup(k => k.OpenSubKey("Microsoft SQL Server Local DB")).Returns(
new System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy(null));
var mockedWow64RegistryKey = new Mock<System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy>();
mockedRegistryKey.Setup(k => k.OpenSubKey("Wow6432Node")).Returns(mockedWow64RegistryKey.Object);
mockedWow64RegistryKey.Setup(k => k.OpenSubKey("Microsoft")).Returns(mockedWow64RegistryKey.Object);
mockedWow64RegistryKey.Setup(k => k.OpenSubKey("Microsoft SQL Server Local DB")).Returns(mockedWow64RegistryKey.Object);
mockedWow64RegistryKey.Setup(k => k.OpenSubKey("Installed Versions")).Returns(mockedWow64RegistryKey.Object);
mockedWow64RegistryKey.Setup(k => k.SubKeyCount).Returns(1);
mockedWow64RegistryKey.Setup(k => k.GetSubKeyNames()).Returns(new[] { "64BitVersion" });
Assert.Equal(
"64BitVersion",
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
mockedRegistryKey.Object,
new Mock<System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy>().Object)
.TryGetLocalDBVersionInstalled());
}
[Fact]
public void SqlServerDetector_disposes_RegisterKey_and_ManagementObjectSearcher_when_it_is_disposed()
{
var mockedRegistryKey = new Mock<System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy>();
var mockedSearcher = new Mock<System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy>();
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(mockedRegistryKey.Object, mockedSearcher.Object).
Dispose();
mockedRegistryKey.Verify(k => k.Dispose());
mockedSearcher.Verify(s => s.Dispose());
}
[Fact]
public void SqlServerDetector_generates_SQL_Express_base_connection_string_if_both_Express_and_LocalDB_are_installed()
{
var specification =
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
CreatedMockedRegistryKey("11.0"), CreateMockedController())
.BuildConnectionFactorySpecification();
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlConnectionFactoryName,
specification.ConnectionFactoryName);
Assert.Empty(specification.ConstructorArguments);
}
[Fact]
public void SqlServerDetector_generates_SQL_Express_base_connection_string_if_Express_is_installed_and_LocalDB_is_not()
{
var specification =
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
CreatedMockedRegistryKey(new string[0]), CreateMockedController())
.BuildConnectionFactorySpecification();
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlConnectionFactoryName,
specification.ConnectionFactoryName);
Assert.Empty(specification.ConstructorArguments);
}
[Fact]
public void SqlServerDetector_generates_LocalDB_base_connection_string_if_LocalDB_is_installed_and_Express_is_not()
{
var specification =
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
CreatedMockedRegistryKey("12.0"), CreateMockedController(status: null))
.BuildConnectionFactorySpecification();
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.LocalDbConnectionFactoryName,
specification.ConnectionFactoryName);
Assert.Equal("v12.0", specification.ConstructorArguments.Single());
}
[Fact]
public void SqlServerDetector_generates_LocalDB_11_base_connection_string_if_neither_LocalDB_or_Express_are_installed()
{
var specification =
new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
CreatedMockedRegistryKey(new string[0]), CreateMockedController(status: null))
.BuildConnectionFactorySpecification();
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.LocalDbConnectionFactoryName,
specification.ConnectionFactoryName);
Assert.Equal("v11.0", specification.ConstructorArguments.Single());
}
[Fact]
public void SqlServerDetector_detects_SQL_Express_on_dev_machine()
{
using (
var detector = new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
new Mock<System.Data.Entity.ConnectionFactoryConfig.RegistryKeyProxy>().Object,
new System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy(
new ServiceController("MSSQL$SQLEXPRESS"))))
{
Assert.True(detector.IsSqlExpressInstalled());
}
}
#if !NET40
[Fact]
public void SqlServerDetector_detects_LocalDB_v11_0_on_dev_machine()
{
using (
var detector = new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
Registry.LocalMachine, new Mock<System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy>().Object)
)
{
Assert.Equal("11.0", detector.TryGetLocalDBVersionInstalled());
}
}
#endif
[Fact]
public void Base_connection_string_on_dev_box_with_SQL_Express_installed_has_SQL_Express_connection_string()
{
using (
var detector = new System.Data.Entity.ConnectionFactoryConfig.SqlServerDetector(
Registry.LocalMachine,
new System.Data.Entity.ConnectionFactoryConfig.ServiceControllerProxy(
new ServiceController("MSSQL$SQLEXPRESS"))))
{
var specification = detector.BuildConnectionFactorySpecification();
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.ConnectionFactorySpecification.SqlConnectionFactoryName,
specification.ConnectionFactoryName);
Assert.Empty(specification.ConstructorArguments);
}
}
[Fact]
public void ConnectionFactoryConfigurator_throws_when_passed_null_Project()
{
Assert.Equal(
"project",
Assert.Throws<ArgumentNullException>(
() => new System.Data.Entity.ConnectionFactoryConfig.ConnectionFactoryConfigurator(null)).ParamName);
}
#endregion
#region Tests using real Visual Studio objects
[Fact]
public void Default_connection_factory_is_added_to_real_Visual_Studio_project_and_config_file()
{
var configFilesFound = new List<string>();
Run_Project_test_if_Visual_Studio_is_running(
p =>
{
new System.Data.Entity.ConnectionFactoryConfig.ConfigFileFinder().FindConfigFiles(
p.ProjectItems, i =>
{
configFilesFound.Add(i.Name);
var config = XDocument.Load(i.FileNames[0]);
// Checked in app.config for unit tests has no connection factory, so one should be added
var modified = new System.Data.Entity.ConnectionFactoryConfig.
ConfigFileManipulator().AddConnectionFactoryToConfig(
config,
new System.Data.Entity.ConnectionFactoryConfig.
ConnectionFactorySpecification(
System.Data.Entity.ConnectionFactoryConfig.
ConnectionFactorySpecification.SqlConnectionFactoryName,
"SomeConnectionString"));
Assert.True(modified);
Assert.Equal(
System.Data.Entity.ConnectionFactoryConfig.
ConnectionFactorySpecification.SqlConnectionFactoryName, GetFactoryName(config));
Assert.Equal("SomeConnectionString", GetArgument(config));
});
Assert.Equal(1, configFilesFound.Count);
Assert.Equal("App.config", configFilesFound.Single());
});
}
[Fact]
public void GetProjectTypes_returns_project_types()
{
Run_Project_test_if_Visual_Studio_is_running(
p =>
{
var types = System.Data.Entity.Migrations.Extensions.ProjectExtensions.GetProjectTypes(p);
Assert.Equal(new[] { "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}" }, types);
});
}
private void Run_Project_test_if_Visual_Studio_is_running(Action<Project> test)
{
MessageFilter.Register();
try
{
var dte = (DTE)Marshal.GetActiveObject("VisualStudio.DTE.11.0");
var project = TryGetPowerShellUnitTests(dte);
if (project != null)
{
test(project);
}
}
catch (COMException)
{
// This is thrown when running as part of a razzle build. The test doesn't work in
// the razzle environment.
}
finally
{
MessageFilter.Revoke();
}
}
private static Project TryGetPowerShellUnitTests(DTE dte)
{
return dte
.Solution
.Projects
.OfType<Project>()
.Where(p => p.Name == "Tests")
.SelectMany(p => p.ProjectItems.OfType<ProjectItem>())
.Where(p => p.Name == "UnitTests")
.Select(p => p.SubProject)
.FirstOrDefault();
}
#endregion
}
#region Fake connection factories
public abstract class FakeBaseConnectionFactory : IDbConnectionFactory
{
public DbConnection CreateConnection(string nameOrConnectionString)
{
throw new NotImplementedException();
}
}
public class FakeConnectionFactoryNoParams : FakeBaseConnectionFactory
{
}
public class FakeConnectionFactoryOneParam : FakeBaseConnectionFactory
{
public string Arg { get; set; }
public FakeConnectionFactoryOneParam(string arg)
{
Arg = arg;
}
}
public class FakeConnectionFactoryManyParams : FakeBaseConnectionFactory
{
public List<string> Args { get; set; }
public FakeConnectionFactoryManyParams(
string arg0, string arg1, string arg2, string arg3, string arg4,
string arg5, string arg6, string arg7, string arg8, string arg9,
string arg10)
{
Args = new List<string>
{
arg0,
arg1,
arg2,
arg3,
arg4,
arg5,
arg6,
arg7,
arg8,
arg9,
arg10
};
}
}
public class FakeNonConnectionFactory
{
}
#endregion
#region Visual Studio threading helpers
/// <summary>
/// This class handles re-tries that can be required when calling into Visual Studio
/// from a non-VS thread.
/// See http://msdn.microsoft.com/en-us/library/ms228772(v=VS.100).aspx
/// </summary>
public class MessageFilter : IOleMessageFilter
{
public static void Register()
{
IOleMessageFilter _;
CoRegisterMessageFilter(new MessageFilter(), out _);
}
public static void Revoke()
{
IOleMessageFilter _;
CoRegisterMessageFilter(null, out _);
}
int IOleMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo)
{
return 0;
}
int IOleMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
{
if (dwRejectType == 2)
{
// Retry the thread call immediately if return >= 0 & < 100.
return 99;
}
// Too busy; cancel call.
return -1;
}
int IOleMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
{
return 2;
}
[DllImport("Ole32.dll")]
private static extern int CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
}
[ComImport]
[Guid("00000016-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IOleMessageFilter
{
[PreserveSig]
int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);
[PreserveSig]
int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
[PreserveSig]
int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
}
#endregion
}