public void TestAddDataReaderWithNullSchema()
        {
            // Creates a MultiShardDataReader and verifies that the right exception is thrown
            Func <LabeledDbDataReader[], bool> createMultiShardReader = (readers) =>
            {
                bool hitNullSchemaException = false;

                try
                {
                    var mockMultiShardCmd    = MultiShardCommand.Create(null, "test");
                    var multiShardDataReader = new MultiShardDataReader(mockMultiShardCmd, readers,
                                                                        MultiShardExecutionPolicy.PartialResults, false, readers.Length);
                }
                catch (MultiShardDataReaderInternalException ex)
                {
                    hitNullSchemaException = ex.Message.Contains("null schema");
                }

                return(hitNullSchemaException);
            };

            var labeledDataReaders = new LabeledDbDataReader[10];

            // Create a few mock readers. All with a null schema
            for (int i = 0; i < labeledDataReaders.Length; i++)
            {
                var mockReader = new MockSqlDataReader(string.Format("Reader{0}", i), null /* Null schema */);
                labeledDataReaders[i] = new LabeledDbDataReader(mockReader,
                                                                new ShardLocation("test", string.Format("Shard{0}", i)), new MockSqlCommand()
                {
                    Connection = new MockSqlConnection("", () => { })
                });
            }

            // Case #1
            bool hitException = createMultiShardReader(labeledDataReaders);

            Assert.IsFalse(hitException, "Unexpected exception! All readers have a null schema.");

            // Case #2
            for (int i = 0; i < labeledDataReaders.Length; i++)
            {
                MockSqlDataReader mockReader = (MockSqlDataReader)labeledDataReaders[i].DbDataReader;
                mockReader.Open();

                if (i > labeledDataReaders.Length / 2)
                {
                    mockReader.DataTable = new DataTable();
                }
            }

            hitException = createMultiShardReader(labeledDataReaders);
            Assert.IsTrue(hitException, "Exception not hit! Second half of readers don't have a null schema!");

            // Case #3
            for (int i = 0; i < labeledDataReaders.Length; i++)
            {
                MockSqlDataReader mockReader = (MockSqlDataReader)labeledDataReaders[i].DbDataReader;
                mockReader.Open();

                if (i < labeledDataReaders.Length / 2)
                {
                    mockReader.DataTable = new DataTable();
                }
                else
                {
                    mockReader.DataTable = null;
                }
            }

            hitException = createMultiShardReader(labeledDataReaders);
            Assert.IsTrue(hitException, "Exception not hit! First half of readers don't have a null schema!");
        }
        public void TestDataReaderReadException()
        {
            // Setup two data readers from shards
            var  mockReader1         = new MockSqlDataReader("Reader1");
            var  mockReader2         = new MockSqlDataReader("Reader2");
            bool movedOnToNextReader = false;
            int  invokeCount         = 1;
            Func <MockSqlDataReader, Task <bool> > ExecuteOnReadAsync = (r) =>
            {
                return(Task.Run <bool>(() =>
                {
                    // First reader throws an exception when Read
                    if (r.Name == "Reader1")
                    {
                        if (invokeCount == 2)
                        {
                            throw new InvalidOperationException();
                        }
                    }
                    else
                    {
                        movedOnToNextReader = true;
                    }
                    return true;
                }));
            };

            Action <MockSqlDataReader> ExecuteOnGetColumn = (r) =>
            {
                if (r.Name == "Reader1")
                {
                    throw new InvalidOperationException();
                }
            };

            mockReader1.ExecuteOnReadAsync = ExecuteOnReadAsync;
            mockReader1.ExecuteOnGetColumn = ExecuteOnGetColumn;
            mockReader2.ExecuteOnReadAsync = ExecuteOnReadAsync;
            var labeledDataReaders = new LabeledDbDataReader[2];

            labeledDataReaders[0] = new LabeledDbDataReader(mockReader1, new ShardLocation("test", "Shard1"),
                                                            new MockSqlCommand()
            {
                Connection = new MockSqlConnection("", () => { })
            });
            labeledDataReaders[1] = new LabeledDbDataReader(mockReader2, new ShardLocation("test", "Shard2"),
                                                            new MockSqlCommand()
            {
                Connection = new MockSqlConnection("", () => { })
            });

            // Create the MultiShardDataReader
            var mockMultiShardCmd    = MultiShardCommand.Create(null, "test");
            var multiShardDataReader = new MultiShardDataReader(mockMultiShardCmd, labeledDataReaders,
                                                                MultiShardExecutionPolicy.PartialResults, false);

            // Validate that if an exception is thrown when reading a column,
            // it is propagated back to the user
            try
            {
                multiShardDataReader.Read();
                invokeCount++;
                multiShardDataReader.GetInt32(0);
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is InvalidOperationException, "Expected InvalidOperationException!");
            }

            // Validate that we didn't automatically move on to the next reader when we
            // hit an exception whilst reading the column and that
            // an exception from a second Read() call is stored and the reader is closed
            multiShardDataReader.Read();
            Assert.AreEqual(multiShardDataReader.MultiShardExceptions.Count, 1, "Expected exception to be recorded");
            Assert.IsTrue(mockReader1.IsClosed, "Expected reader to be closed!");

            // Validate we immediately moved on to the next reader
            multiShardDataReader.Read();
            Assert.IsTrue(movedOnToNextReader, "Should've moved on to next reader");
        }