// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. namespace System.Data.Entity { using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Configuration; using System.Data.Common; using System.Data.Entity.Config; using System.Data.Entity.Core.EntityClient; using System.Data.Entity.Core.Metadata.Edm; using System.Data.Entity.Core.Objects; using System.Data.Entity.Infrastructure; using System.Data.Entity.Internal.ConfigFile; using System.Data.Entity.SqlServer; using System.Data.Entity.TestHelpers; using System.Data.SqlClient; using System.IO; using System.Reflection; using System.Threading.Tasks; using System.Transactions; using System.Xml.Linq; public class TestBase : MarshalByRefObject { static TestBase() { DbConfiguration.SetConfiguration(new FunctionalTestsConfiguration()); } internal DbDatabaseMapping BuildMapping(DbModelBuilder modelBuilder) { OnModelCreating(modelBuilder); // Build and clone to check for idempotency issues. modelBuilder.Build(ProviderRegistry.Sql2008_ProviderInfo); var clone = modelBuilder.Clone(); return clone.Build(ProviderRegistry.Sql2008_ProviderInfo).DatabaseMapping; } protected virtual void OnModelCreating(DbModelBuilder modelBuilder) { // For fixture wide configuration } internal DbDatabaseMapping BuildCeMapping(DbModelBuilder modelBuilder) { // Build and clone to check for idempotency issues. modelBuilder.Build(ProviderRegistry.SqlCe4_ProviderInfo); var clone = modelBuilder.Clone(); return clone.Build(ProviderRegistry.SqlCe4_ProviderInfo).DatabaseMapping; } protected static DataRow CreateProviderRow(string name, string invariantName, string assemblyQualifiedName) { var table = new DataTable(); table.Columns.AddRange( new[] { new DataColumn("Name", typeof(string)), new DataColumn("Description", typeof(string)), new DataColumn("InvariantName", typeof(string)), new DataColumn("AssemblyQualifiedName", typeof(string)), }); var row = table.NewRow(); row["Name"] = name; row["Description"] = "Name: " + name + " Invariant: " + invariantName; row["InvariantName"] = invariantName; row["AssemblyQualifiedName"] = assemblyQualifiedName; return row; } protected static void RunTestWithTempMetadata(string csdl, string ssdl, string msl, Action> test) { var paths = new[] { Path.GetTempFileName() + ".ssdl", Path.GetTempFileName() + ".csdl", Path.GetTempFileName() + ".msl" }; var metadata = new[] { ssdl, csdl, msl }; try { for (var i = 0; i < metadata.Length; i++) { using (var file = File.CreateText(paths[i])) { file.Write(metadata[i]); } } test(paths); } finally { foreach (var path in paths) { try { File.SetAttributes(path, File.GetAttributes(path) & ~FileAttributes.ReadOnly); File.Delete(path); } catch (FileNotFoundException) { } } } } #region Assemblies and exceptions /// /// The assembly containing Code First and the Productivity API. /// public static Assembly EntityFrameworkAssembly { get { return typeof(DbModelBuilder).Assembly; } } /// /// System.ComponentModel.DataAnnotations. /// public static Assembly SystemComponentModelDataAnnotationsAssembly { get { return typeof(ValidationAttribute).Assembly; } } /// /// EntityFramework.SqlServer /// public static Assembly EntityFrameworkSqlServerAssembly { get { return typeof(SqlProviderServices).Assembly; } } /// /// Gets an embedded resource string from the specified assembly /// public static string LookupString(Assembly assembly, string resourceTable, string resourceKey) { return new AssemblyResourceLookup(assembly, resourceTable).LookupString(resourceKey); } /// /// Executes the given delegate and returns the exception that it throws. /// protected Exception GenerateException(Action willThrow) { return ExceptionHelpers.GenerateException(willThrow); } /// /// Executes the given test multiple times in parallel. /// /// The test. /// The number of copies to run in parallel. protected static void ExecuteInParallel(Action test, int count = 20) { var tests = new Action[count]; for (var i = 0; i < count; i++) { tests[i] = test; } Parallel.Invoke(tests); } #endregion #region GetObjectContext /// /// Returns the ObjectContext for the given DbContext. /// public static ObjectContext GetObjectContext(DbContext context) { return ((IObjectContextAdapter)context).ObjectContext; } #endregion #region State entry helpers /// /// Gets all GetStateEntries for the given DbContext,. /// /// A DbContext instance. /// All state entries in the ObjectStateManager. protected static IEnumerable GetStateEntries(DbContext dbContext) { return ModelHelpers.GetStateEntries(dbContext); } /// /// Gets all GetStateEntries for the given ObjectContext,. /// /// A ObjectContext instance. /// All state entries in the ObjectStateManager. protected static IEnumerable GetStateEntries(ObjectContext objectContext) { return ModelHelpers.GetStateEntries(objectContext); } /// /// Gets the ObjectStateEntry for the given entity in the given DbContext. /// /// A DbContext instance. /// The entity to lookup. /// The ObjectStateEntry. protected static ObjectStateEntry GetStateEntry(DbContext dbContext, object entity) { return ModelHelpers.GetStateEntry(dbContext, entity); } /// /// Gets the ObjectStateEntry for the given entity in the given ObjectContext. /// /// A ObjectContext instance. /// The entity to lookup. /// The ObjectStateEntry. protected static ObjectStateEntry GetStateEntry(ObjectContext objectContext, object entity) { return ModelHelpers.GetStateEntry(objectContext, entity); } /// /// Asserts that there's no ObjectStateEntry for the given entity in the given DbContext. /// /// A DbContext instance. /// The entity to lookup. public static void AssertNoStateEntry(DbContext dbContext, object entity) { ModelHelpers.AssertNoStateEntry(dbContext, entity); } /// /// Asserts that there's no ObjectStateEntry for the given entity in the given ObjectContext. /// /// A ObjectContext instance. /// The entity to lookup. public static void AssertNoStateEntry(ObjectContext objectContext, object entity) { ModelHelpers.AssertNoStateEntry(objectContext, entity); } #endregion #region Connection helpers /// /// Returns a simple SQL Server connection string to the local machine with the given database name. /// /// The database name. /// The connection string. protected static string SimpleConnectionString(string databaseName) { return ModelHelpers.SimpleConnectionString(databaseName); } /// /// Returns a simple SQL Server connection string with the specified credentials. /// /// The database name. /// User ID to be use when connecting to SQL Server. /// Password for the SQL Server account. /// /// Indicates if security-sensitive information is not returned as part of the /// connection if the connection has ever been opened. /// /// The connection string. protected static string SimpleConnectionStringWithCredentials( string databaseName, string userId, string password, bool persistSecurityInfo = false) { return ModelHelpers.SimpleConnectionStringWithCredentials( databaseName, userId, password, persistSecurityInfo); } /// /// Returns the default name that will be created for the context of the given type. /// /// The type of the context to create a name for. /// The name. protected static string DefaultDbName() where TContext : DbContext { return ModelHelpers.DefaultDbName(); } /// /// Returns the transaction count from the server. /// /// Database connection to connect against. /// The transaction count. protected int GetTransactionCount(DbConnection connection) { var closeconn = false; if (connection.State != ConnectionState.Open) { connection.Open(); closeconn = true; } var cmd = connection.CreateCommand(); cmd.CommandText = "select @@TranCount"; var trancount = (int)cmd.ExecuteScalar(); if (closeconn) { connection.Close(); } return trancount; } /// /// Returns a local transaction. /// /// /// protected DbTransaction BeginLocalTransaction(DbContext context) { return OpenEntityConnection(context).BeginTransaction(); } /// /// Opens the underlying obtained from the underlying /// and creates a new . /// /// /// protected CommittableTransaction BeginCommittableTransaction(DbContext context) { OpenEntityConnection(context); return new CommittableTransaction(); } /// /// Opens the underlying obtained from the underlying /// and returns it. /// /// The context. /// The connection. private static EntityConnection OpenEntityConnection(DbContext context) { var connection = (EntityConnection)((IObjectContextAdapter)context).ObjectContext.Connection; if (connection.State != ConnectionState.Open) { connection.Open(); } return connection; } /// /// Closes the underlying obtained from the underlying /// if the connection is open. /// protected void CloseEntityConnection(DbContext context) { var connection = ((IObjectContextAdapter)context).ObjectContext.Connection; if (connection.State == ConnectionState.Open) { connection.Close(); } } /// /// Returns a simple SQL Server connection string to the local machine for the given context type. /// /// The type of the context to create a connection string for. /// The connection string. protected static string SimpleConnectionString() where TContext : DbContext { return ModelHelpers.SimpleConnectionString(); } /// /// Returns a simple SQL Server connection string to the local machine using attached database for the given context type. /// /// The type of the context to create a connection string for. /// The connection string. protected static string SimpleAttachConnectionString() where TContext : DbContext { return ModelHelpers.SimpleAttachConnectionString(); } /// /// Returns a simple SQLCE connection string to the local machine for the given context type. /// /// The type of the context. /// The connection string. protected static string SimpleCeConnectionString() where TContext : DbContext { return ModelHelpers.SimpleCeConnectionString(); } /// /// Returns a simple SQL Server connection to the local machine for the given context type. /// /// The type of the context to create a connection for. /// The connection. protected static SqlConnection SimpleConnection() where TContext : DbContext { return ModelHelpers.SimpleConnection(); } /// /// Returns a simple SQL CE connection for the given context type. /// /// The type of the context to create a connection for. /// The connection. protected static DbConnection SimpleCeConnection() where TContext : DbContext { return ModelHelpers.SimpleCeConnection(); } #endregion #region Entity set name helpers /// /// Gets the entity set name for the given CLR type, assuming no MEST. /// /// The context to look in. /// The type to lookup. /// The entity set name. protected static string GetEntitySetName(DbContext dbContext, Type clrType) { return ModelHelpers.GetEntitySetName(dbContext, clrType); } /// /// Gets the entity set name for the given CLR type, assuming no MEST. /// /// The context to look in. /// The type to lookup. /// The entity set name. protected static string GetEntitySetName(ObjectContext objetContext, Type clrType) { return ModelHelpers.GetEntitySetName(objetContext, clrType); } #endregion #region Entity Type helpers /// /// Gets the EntityType of the given CLR type /// /// The context to look in. /// The CLR type /// The entity type corresponding to the CLR type protected static EntityType GetEntityType(DbContext dbContext, Type clrType) { return ModelHelpers.GetEntityType(dbContext, clrType); } /// /// Gets the EntityType of the given CLR type /// /// The context to look in. /// The CLR type /// The entity type corresponding to the CLR type protected static EntityType GetEntityType(ObjectContext objectContext, Type clrType) { return ModelHelpers.GetStructuralType(objectContext, clrType); } #endregion #region Creating config documents public static Configuration CreateEmptyConfig() { var tempFileName = Path.GetTempFileName(); var doc = new XDocument(new XElement("configuration")); doc.Save(tempFileName); var config = ConfigurationManager.OpenMappedExeConfiguration( new ExeConfigurationFileMap { ExeConfigFilename = tempFileName }, ConfigurationUserLevel.None); config.Sections.Add("entityFramework", new EntityFrameworkSection()); return config; } #endregion } }