Beispiel #1
0
        /// <summary>
        /// Returns a random existing Primary Key value
        /// </summary>
        private int GetRandomPK(Random rnd, TableMetadata table)
        {
            using (DataStressConnection conn = CreateConnection())
            {
                conn.Open();

                // This technique to get a random row comes from http://www.4guysfromrolla.com/webtech/042606-1.shtml
                // When you set rowcount and then select into a scalar value, then the query is optimised so that
                // just the last value is selected. So if n = ROWCOUNT then the query returns the n'th row.

                int rowNumber = rnd.Next(Depth);

                DbCommand com     = conn.CreateCommand();
                string    cmdText = string.Format(
                    @"SET ROWCOUNT {0};
                          DECLARE @PK INT;
                          SELECT @PK = PrimaryKey FROM {1} WITH(NOLOCK)
                          SELECT @PK", rowNumber, table.TableName);

                com.CommandText = cmdText;

                object result = com.ExecuteScalarSyncOrAsync(CancellationToken.None, rnd).Result;
                if (result == DBNull.Value)
                {
                    throw DataStressErrors.TestError(string.Format("Table {0} returned DBNull for primary key", table.TableName));
                }
                else
                {
                    int primaryKey = (int)result;
                    return(primaryKey);
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Returns a random command object
        /// </summary>
        public DbCommand GetCommand(Random rnd, TableMetadata table, DataStressConnection conn, bool query, bool isXml = false)
        {
            if (query)
            {
                return(GetSelectCommand(rnd, table, conn, isXml));
            }
            else
            {
                // make sure arguments are correct
                DataStressErrors.Assert(!isXml, "wrong usage of GetCommand: cannot create command with FOR XML that is not query");

                int select = rnd.Next(4);
                switch (select)
                {
                case 0:
                    return(GetUpdateCommand(rnd, table, conn));

                case 1:
                    return(GetInsertCommand(rnd, table, conn));

                case 2:
                    return(GetDeleteCommand(rnd, table, conn));

                default:
                    return(GetSelectCommand(rnd, table, conn));
                }
            }
        }
Beispiel #3
0
        public virtual void GlobalTestSetup()
        {
            // Preconditions - ensure this setup is only called once
            DataStressErrors.Assert(string.IsNullOrEmpty(s_scenario), "Scenario was already set");
            DataStressErrors.Assert(s_source == null, "Source was already set");
            DataStressErrors.Assert(s_factory == null, "Factory was already set");

            // Set m_scenario
            string userProvidedScenario;

            TestMetrics.Overrides.TryGetValue("scenario", out userProvidedScenario);
            // Empty means default scenario for the test group
            s_scenario = (userProvidedScenario ?? string.Empty);
            s_scenario = s_scenario.ToUpperInvariant();

            // Set m_source
            // Empty means that test group will peek the default data source from the config file based on the scenario
            string userProvidedSourceName;

            if (TestMetrics.Overrides.TryGetValue("source", out userProvidedSourceName))
            {
                s_source = DataStressSettings.Instance.GetSourceByName(userProvidedSourceName);
            }

            // Set m_factory
            s_factory = CreateFactory(ref s_scenario, ref s_source);
            s_factory.InitializeSharedData(s_source);

            // Postconditions
            DataStressErrors.Assert(!string.IsNullOrEmpty(s_scenario), "Scenario was not set");
            DataStressErrors.Assert(s_source != null, "Source was not set");
            DataStressErrors.Assert(s_factory != null, "Factory was not set");
        }
Beispiel #4
0
        private void HandleObjectDisposedException(ObjectDisposedException e, bool async)
        {
            // Race condition in DbConnectionFactory.TryGetConnection results in an ObjectDisposedException when calling OpenAsync on a non-pooled connection
            string methodName = async ? "OpenAsync()" : "Open()";

            throw DataStressErrors.ProductError(
                      "Hit ObjectDisposedException in SqlConnection." + methodName, e);
        }
Beispiel #5
0
        public void TestCommandTimeout()
        {
            Random rnd = RandomInstance;
            DataStressConnection conn = null;

            try
            {
                // Use a transaction 50% of the time
                if (rnd.NextBool())
                {
                }

                // Create a select command
                conn = Factory.CreateConnection(rnd);
                if (!OpenConnection(conn))
                {
                    return;
                }
                DataStressFactory.TableMetadata table = Factory.GetRandomTable(rnd);
                DbCommand com = Factory.GetSelectCommand(rnd, table, conn);

                // Setup timeout. We want to see various possibilities of timeout happening before, after, or at the same time as when the result comes in.
                int delay   = rnd.Next(0, 10); // delay is from 0 to 9 seconds inclusive
                int timeout = rnd.Next(1, 10); // timeout is from 1 to 9 seconds inclusive
                com.CommandText   += string.Format("; WAITFOR DELAY '00:00:0{0}'", delay);
                com.CommandTimeout = timeout;

                // Execute command and catch timeout exception
                try
                {
                    CommandExecute(rnd, com, true);
                }
                catch (DbException e)
                {
                    if (e is SqlException && ((SqlException)e).Number == 3989)
                    {
                        throw DataStressErrors.ProductError("Timing issue between OnTimeout and ReadAsyncCallback results in SqlClient's packet parsing going out of sync", e);
                    }
                    else if (!e.Message.ToLower().Contains("timeout"))
                    {
                        throw;
                    }
                }
            }
            finally
            {
                if (conn != null)
                {
                    conn.Dispose();
                }
            }
        }
Beispiel #6
0
        /// <summary>
        /// Creates a new connection and initializes it with random connection string generated from the factory's source
        /// Note: if rnd is null, create a connection with minimal string required to connect to the target database
        /// </summary>
        /// <param name="rnd">Randomizes Connection Pool enablement, the application Name to randomize connection pool</param>
        /// <param name="options"></param>
        /// <returns></returns>
        public DataStressConnection CreateConnection(Random rnd = null, ConnectionStringOptions options = ConnectionStringOptions.Default)
        {
            // Determine connection options (connection string, identity, etc)
            string connectionString     = CreateBaseConnectionString(rnd, options);
            bool   clearPoolBeforeClose = false;

            if (rnd != null)
            {
                // Connection string and/or identity are randomized

                // We implement this using the Application Name field in the connection string since this field
                // should not affect behaviour other than connection pooling, since all connections in a pool
                // must have the exact same connection string (including Application Name)

                if (rnd.NextBool(.1))
                {
                    // Disable pooling
                    connectionString = connectionString + ";Pooling=false;";
                }
                else if (rnd.NextBool(0.001))
                {
                    // Use a unique Application Name to get a new connection from a new pool. We do this in order to
                    // stress the code that creates/deletes pools.
                    connectionString = string.Format("{0}; Pooling=true; Application Name=\"{1}\";", connectionString, GetRandomApplicationName());

                    // Tell DataStressConnection to call SqlConnection.ClearPool when closing the connection. This ensures
                    // we do not keep a large number of connections in the pool that we will never use again.
                    clearPoolBeforeClose = true;
                }
                else
                {
                    switch (CurrentPoolingStressMode)
                    {
                    case PoolingStressMode.RandomizeConnectionStrings:
                        // Use one of the pre-generated Application Names in order to get a pooled connection with a randomized connection string
                        connectionString = string.Format("{0}; Pooling=true; Application Name=\"{1}\";", connectionString, _applicationNames[rnd.Next(_applicationNames.Count)]);
                        break;

                    default:
                        throw DataStressErrors.UnhandledCaseError(CurrentPoolingStressMode);
                    }
                }
            }

            // All options have been determined, now create
            DbConnection con = DbFactory.CreateConnection();

            con.ConnectionString = connectionString;
            return(new DataStressConnection(con, clearPoolBeforeClose));
        }
Beispiel #7
0
        /// <summary>
        /// Kills the given connection using "kill [spid]" if the parameter is nonzero
        /// </summary>
        private void KillConnection()
        {
            DataStressErrors.Assert(_spid != 0, "Called KillConnection with spid != 0");

            using (var killerConn = DataTestGroup.Factory.CreateConnection())
            {
                killerConn.Open();

                using (var killerCmd = killerConn.CreateCommand())
                {
                    killerCmd.CommandText = "begin try kill " + _spid + " end try begin catch end catch";
                    killerCmd.ExecuteNonQuery();
                }
            }
        }
Beispiel #8
0
        protected virtual object GetRandomData(Random rnd, DbType dbType, int maxLength)
        {
            byte[] buffer;
            switch (dbType)
            {
            case DbType.Boolean:
                return(rnd.Next(2) == 0 ? false : true);

            case DbType.Byte:
                return(rnd.Next(byte.MinValue, byte.MaxValue + 1));

            case DbType.Int16:
                return(rnd.Next(short.MinValue, short.MaxValue + 1));

            case DbType.Int32:
                return(rnd.Next(2) == 0 ? int.MaxValue / rnd.Next(1, 3) : int.MinValue / rnd.Next(1, 3));

            case DbType.Int64:
                return(rnd.Next(2) == 0 ? long.MaxValue / rnd.Next(1, 3) : long.MinValue / rnd.Next(1, 3));

            case DbType.Single:
                return(rnd.NextDouble() * (rnd.Next(2) == 0 ? float.MaxValue : float.MinValue));

            case DbType.Double:
                return(rnd.NextDouble() * (rnd.Next(2) == 0 ? double.MaxValue : double.MinValue));

            case DbType.Decimal:
                return(rnd.Next(short.MinValue, short.MaxValue + 1));

            case DbType.DateTime:
            case DbType.DateTime2:
                return(DateTime.Now);

            case DbType.Date:
                return(DateTime.Now.Date);

            case DbType.Time:
                return(DateTime.Now.TimeOfDay.ToString("c"));

            case DbType.DateTimeOffset:
                return(DateTimeOffset.Now);

            case DbType.Guid:
                buffer = new byte[16];
                rnd.NextBytes(buffer);
                return(new Guid(buffer));

            case DbType.Object:
            case DbType.Binary:
                rnd.NextBytes(buffer = new byte[rnd.Next(1, maxLength)]);
                return(buffer);

            case DbType.String:
            case DbType.Xml:
                string openTag   = "<Data>";
                string closeTag  = "</Data>";
                int    tagLength = openTag.Length + closeTag.Length;

                if (tagLength > maxLength)
                {
                    // Case (1): tagLength > maxTargetLength
                    return("");
                }
                else
                {
                    StringBuilder builder = new StringBuilder(maxLength);

                    builder.Append(openTag);

                    // The data is just a repeat of one character because to the managed provider
                    // it is only really the length that matters, not the content of the data
                    char characterToUse = (char)rnd.Next((int)'@', (int)'~'); // Choosing random characters in this range to avoid special
                                                                              // xml chars like '<' or '&'
                    int numRepeats = rnd.Next(0, maxLength - tagLength);      // Case (2): tagLength == maxTargetLength
                                                                              // Case (3): tagLength < maxTargetLength <-- most common
                    builder.Append(characterToUse, numRepeats);

                    builder.Append(closeTag);

                    DataStressErrors.Assert(builder.Length <= maxLength, "Incorrect length of randomly generated string");

                    return(builder.ToString());
                }

            default:
                throw DataStressErrors.UnhandledCaseError(dbType);
            }
        }
Beispiel #9
0
        private DbType GetDbType(TableColumn column)
        {
            switch (column.ColumnName)
            {
            case "bit_FLD": return(DbType.Boolean);

            case "tinyint_FLD": return(DbType.Byte);

            case "smallint_FLD": return(DbType.Int16);

            case "int_FLD": return(DbType.Int32);

            case "PrimaryKey": return(DbType.Int32);

            case "bigint_FLD": return(DbType.Int64);

            case "real_FLD": return(DbType.Single);

            case "float_FLD": return(DbType.Double);

            case "smallmoney_FLD": return(DbType.Decimal);

            case "money_FLD": return(DbType.Decimal);

            case "decimal_FLD": return(DbType.Decimal);

            case "numeric_FLD": return(DbType.Decimal);

            case "datetime_FLD": return(DbType.DateTime);

            case "smalldatetime_FLD": return(DbType.DateTime);

            case "datetime2_FLD": return(DbType.DateTime2);

            case "timestamp_FLD": return(DbType.Binary);

            case "date_FLD": return(DbType.Date);

            case "time_FLD": return(DbType.Time);

            case "datetimeoffset_FLD": return(DbType.DateTimeOffset);

            case "uniqueidentifier_FLD": return(DbType.Guid);

            case "sql_variant_FLD": return(DbType.Object);

            case "image_FLD": return(DbType.Binary);

            case "varbinary_FLD": return(DbType.Binary);

            case "binary_FLD": return(DbType.Binary);

            case "char_FLD": return(DbType.String);

            case "varchar_FLD": return(DbType.String);

            case "text_FLD": return(DbType.String);

            case "ntext_FLD": return(DbType.String);

            case "nvarchar_FLD": return(DbType.String);

            case "nchar_FLD": return(DbType.String);

            case "nvarcharmax_FLD": return(DbType.String);

            case "varbinarymax_FLD": return(DbType.Binary);

            case "varcharmax_FLD": return(DbType.String);

            case "xml_FLD": return(DbType.Xml);

            default: throw DataStressErrors.UnhandledCaseError(column.ColumnName);
            }
        }
Beispiel #10
0
 protected DataStressFactory(DbProviderFactory factory)
 {
     DataStressErrors.Assert(factory != null, "Argument to DataStressFactory constructor is null");
     this.DbFactory = factory;
 }