1 // ConnectionManager.cs - Singleton ConnectionManager class to manage
2 // database connections for test cases.
5 // Sureshkumar T (tsureshkumar@novell.com)
7 // Copyright Novell Inc., and the individuals listed on the
11 // Permission is hereby granted, free of charge, to any person
12 // obtaining a copy of this software and associated documentation
13 // files (the "Software"), to deal in the Software without
14 // restriction, including without limitation the rights to use, copy,
15 // modify, merge, publish, distribute, sublicense, and/or sell copies
16 // of the Software, and to permit persons to whom the Software is
17 // furnished to do so, subject to the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
26 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 using System.Collections.Generic;
34 using System.Data.Common;
36 using System.Data.Odbc;
38 using System.Data.SqlClient;
41 using System.Text.RegularExpressions;
42 using NUnit.Framework;
44 namespace MonoTests.System.Data.Connected
46 public class ConnectionManager
48 private static ConnectionManager instance;
49 private ConnectionHolder<SqlConnection> sql;
51 private const string OdbcEnvVar = "SYSTEM_DATA_ODBC_V2";
52 private const string SqlEnvVar = "SYSTEM_DATA_MSSQL_V2";
54 private ConnectionManager ()
56 //Environment.SetEnvironmentVariable(OdbcEnvVar, @"Driver={MySQL ODBC 5.3 Unicode Driver};server=127.0.0.1;uid=sa;pwd=qwerty123;");
57 //Environment.SetEnvironmentVariable(SqlEnvVar, @"server=127.0.0.1;database=master;user id=sa;password=qwerty123");
59 // Generate a random db name
60 DatabaseName = "monotest" + Guid.NewGuid().ToString().Substring(0, 7);
62 sql = CreateSqlConfig (SqlEnvVar);
64 CreateMssqlDatabase();
67 odbc = CreateOdbcConfig (OdbcEnvVar);
69 CreateMysqlDatabase();
73 static ConnectionHolder<SqlConnection> CreateSqlConfig (string envVarName)
75 string connectionString = Environment.GetEnvironmentVariable (envVarName);
76 if (string.IsNullOrEmpty (connectionString))
79 SqlConnection connection;
81 connection = new SqlConnection ();
83 DbProviderFactory factory = DbProviderFactories.GetFactory ("System.Data.SqlClient");
84 connection = (SqlConnection)factory.CreateConnection ();
87 var engine = new EngineConfig {
88 Type = EngineType.SQLServer,
90 QuoteCharacter = """,
91 SupportsMicroseconds = true,
92 SupportsUniqueIdentifier = true,
93 SupportsTimestamp = true,
96 return new ConnectionHolder<SqlConnection> (engine, connection, connectionString);
100 static ConnectionHolder<OdbcConnection> CreateOdbcConfig (string envVarName)
102 string connectionString = Environment.GetEnvironmentVariable (envVarName);
103 if (string.IsNullOrEmpty (connectionString))
106 DbProviderFactory factory = DbProviderFactories.GetFactory ("System.Data.Odbc");
107 var connection = (OdbcConnection)factory.CreateConnection ();
109 var engine = new EngineConfig {
110 Type = EngineType.MySQL,
111 QuoteCharacter = "`",
112 RemovesTrailingSpaces = true,
113 EmptyBinaryAsNull = true,
118 return new ConnectionHolder<OdbcConnection> (engine, connection, connectionString);
122 private void CreateMssqlDatabase()
124 DBHelper.ExecuteNonQuery(sql.Connection, $"CREATE DATABASE [{DatabaseName}]");
125 sql.ConnectionString = sql.ConnectionString.Replace(sql.Connection.Database, DatabaseName);
126 sql.CloseConnection();
128 string query = File.ReadAllText(@"Test/ProviderTests/sql/sqlserver.sql");
130 var queries = SplitSqlStatements(query);
131 foreach (var subQuery in queries)
133 DBHelper.ExecuteNonQuery(sql.Connection, subQuery);
138 private void CreateMysqlDatabase()
140 DBHelper.ExecuteNonQuery(odbc.Connection, $"CREATE DATABASE {DatabaseName}");
141 odbc.Connection.ChangeDatabase(DatabaseName);
142 odbc.ConnectionString += $"database={DatabaseName}";
144 string query = File.ReadAllText("Test/ProviderTests/sql/MySQL_5.sql");
146 var groups = query.Replace("delimiter ", "")
147 .Split(new[] { "//\n" }, StringSplitOptions.RemoveEmptyEntries);
149 foreach (var subQuery in groups[0].Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries).Concat(groups.Skip(1)))
151 DBHelper.ExecuteNonQuery(odbc.Connection, subQuery);
156 private void DropMssqlDatabase()
158 sql.Connection.ChangeDatabase("master");
159 string query = $"ALTER DATABASE [{DatabaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;\nDROP DATABASE [{DatabaseName}]";
160 DBHelper.ExecuteNonQuery(sql.Connection, query);
164 private void DropMysqlDatabase()
166 string query = $"DROP DATABASE [{DatabaseName}]";
167 DBHelper.ExecuteNonQuery(odbc.Connection, query);
171 // Split SQL script by "GO" statements
172 private static IEnumerable<string> SplitSqlStatements(string sqlScript)
174 var statements = Regex.Split(sqlScript,
175 $@"^[\t ]*GO[\t ]*\d*[\t ]*(?:--.*)?$",
176 RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase);
177 return statements.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim(' ', '\r', '\n'));
180 public static ConnectionManager Instance => instance ?? (instance = new ConnectionManager());
182 public string DatabaseName { get; }
186 private ConnectionHolder<OdbcConnection> odbc;
188 public ConnectionHolder<OdbcConnection> Odbc
193 Assert.Ignore($"{OdbcEnvVar} environment variable is not set");
199 public ConnectionHolder<SqlConnection> Sql
204 Assert.Ignore($"{SqlEnvVar} environment variable is not set");
211 sql?.CloseConnection();
213 odbc?.CloseConnection();
218 public class ConnectionHolder<TConnection> where TConnection : DbConnection
220 private TConnection connection;
222 public EngineConfig EngineConfig { get; }
224 public TConnection Connection
228 if (!(connection.State == ConnectionState.Closed ||
229 connection.State == ConnectionState.Broken))
231 connection.ConnectionString = ConnectionString;
237 public void CloseConnection()
239 if (connection != null && connection.State != ConnectionState.Closed)
243 public string ConnectionString { get; set; }
245 public ConnectionHolder(EngineConfig engineConfig, TConnection connection, string connectionString)
247 EngineConfig = engineConfig;
248 this.connection = connection;
249 ConnectionString = connectionString;
252 public bool IsAzure => ConnectionString.ToLower().Contains("database.windows.net");