/// <summary> /// Returns a correct implementation of the persistence provider according to environment variables. /// </summary> /// <remarks>If the environment invariants have failed to hold upon creation of the storage provider, /// a <em>null</em> value will be provided.</remarks> public async Task<IStorageProvider> GetStorageProvider(string storageInvariant) { //Make sure the environment invariants hold before trying to give a functioning SUT instantiation. //This is done instead of the constructor to have more granularity on how the environment should be initialized. try { using(await StorageLock.LockAsync()) { if(AdoNetInvariants.Invariants.Contains(storageInvariant)) { if(!StorageProviders.ContainsKey(storageInvariant)) { Storage = Invariants.EnsureStorageForTesting(Invariants.ActiveSettings.ConnectionStrings.First(i => i.StorageInvariant == storageInvariant)); var properties = new Dictionary<string, string>(); properties["DataConnectionString"] = Storage.Storage.ConnectionString; properties["AdoInvariant"] = storageInvariant; var config = new ProviderConfiguration(properties, null); var storageProvider = new AdoNetStorageProvider(); await storageProvider.Init(storageInvariant + "_StorageProvider", DefaultProviderRuntime, config); StorageProviders[storageInvariant] = storageProvider; } } } } catch { StorageProviders.Add(storageInvariant, null); } return StorageProviders[storageInvariant]; }
public static void ClassInitialize(TestContext testContext) { TraceLogger.AddTraceLevelOverride("RelationalStreamingTests", Severity.Verbose3); try { SqlServerStorage = RelationalStorageForTesting.SetupInstance(AdoNetInvariants.InvariantNameSqlServer, testDatabaseName).GetAwaiter().GetResult(); } catch(Exception ex) { Console.WriteLine("Failed to initialize SQL Server for RelationalGeneralTests: {0}", ex); } try { MySqlStorage = RelationalStorageForTesting.SetupInstance(AdoNetInvariants.InvariantNameMySql, testDatabaseName).GetAwaiter().GetResult(); } catch(Exception ex) { Console.WriteLine("Failed to initialize MySQL for RelationalGeneralTests: {0}", ex); } }
private static Task CancellationTokenTest(RelationalStorageForTesting sut, TimeSpan timeoutLimit) { using(var tokenSource = new CancellationTokenSource(timeoutLimit)) { try { //Here one second is added to the task timeout limit in order to account for the delays. //The delays are mainly in the underlying ADO.NET libraries and database. var task = sut.Storage.ReadAsync<int>(sut.CancellationTestQuery, tokenSource.Token); if(!task.Wait(timeoutLimit.Add(TimeSpan.FromSeconds(1)))) { Assert.Fail(string.Format("Timeout limit {0} ms exceeded.", timeoutLimit.TotalMilliseconds)); } } catch(Exception ex) { //There can be a DbException due to the operation being forcefully cancelled... //... Unless this is a test for a provider which does not support for cancellation. if(sut.Storage.SupportsCommandCancellation()) { //If the operation is cancelled already before database calls, a OperationCancelledException //will be thrown in any case. Assert.IsTrue(ex is DbException || ex is OperationCanceledException, "Unexcepted exception: {0}", ex); } else { Assert.IsTrue(ex is OperationCanceledException, "Unexcepted exception: {0}", ex); } } } return TaskDone.Done; }
private static async Task<StreamingTest> ReadFromDatabaseUsingAsyncStream(RelationalStorageForTesting sut, int streamId, CancellationToken cancellationToken) { return (await sut.Storage.ReadAsync(sut.StreamTestSelect, command => { var p = command.CreateParameter(); p.ParameterName = "streamId"; p.Value = streamId; command.Parameters.Add(p); }, async (selector, resultSetCount, canellationToken) => { var streamSelector = (DbDataReader)selector; var id = await streamSelector.GetValueAsync<int>("Id"); using(var ms = new MemoryStream()) { using(var downloadStream = streamSelector.GetStream(1, sut.Storage)) { await downloadStream.CopyToAsync(ms); return new StreamingTest { Id = id, StreamData = ms.ToArray() }; } } }, cancellationToken, CommandBehavior.SequentialAccess).ConfigureAwait(false)).Single(); }
private static async Task InsertIntoDatabaseUsingStream(RelationalStorageForTesting sut, int streamId, byte[] dataToInsert, CancellationToken cancellationToken) { //The dataToInsert could be inserted here directly, but it wouldn't be streamed. using(var ms = new MemoryStream(dataToInsert)) { await sut.Storage.ExecuteAsync(sut.StreamTestInsert, command => { var p1 = command.CreateParameter(); p1.ParameterName = "Id"; p1.Value = streamId; command.Parameters.Add(p1); //MySQL does not support streams in and for the time being there //is not a custom stream defined. For ideas, see http://dev.mysql.com/doc/refman/5.7/en/blob.html //for string operations for blobs and http://rusanu.com/2010/12/28/download-and-upload-images-from-sql-server-with-asp-net-mvc/ //on how one could go defining one. var p2 = command.CreateParameter(); p2.ParameterName = "StreamData"; p2.Value = dataToInsert; p2.DbType = DbType.Binary; p2.Size = dataToInsert.Length; command.Parameters.Add(p2); }, cancellationToken, CommandBehavior.SequentialAccess).ConfigureAwait(false); } }
private static Task<bool>[] InsertAndReadStreamsAndCheckMatch(RelationalStorageForTesting sut, int streamSize, int countOfStreams, CancellationToken cancellationToken) { //Stream in and steam out three binary streams in parallel. var streamChecks = new Task<bool>[countOfStreams]; var sr = new SafeRandom(); for(int i = 0; i < countOfStreams; ++i) { int streamId = i; streamChecks[i] = Task.Run(async () => { var rb = new byte[streamSize]; sr.NextBytes(rb); await InsertIntoDatabaseUsingStream(sut, streamId, rb, cancellationToken); var dataStreamFromTheDb = await ReadFromDatabaseUsingAsyncStream(sut, streamId, cancellationToken); return dataStreamFromTheDb.StreamData.SequenceEqual(rb); }); } return streamChecks; }