public async Task DisposedTransactionDoesntLeak() { // This test ensures that a transaction that had neither commit nor rollback called does // not leak its transaction state to a subsequent transaction. // The way this works currently is that every session added to the pool gets its state cleared. // The reserved session in SpannerConnection can only be used for readonly transactions and is // therefore immune to this bug. However if that every changes, this test will catch it. using (var connection = _fixture.GetConnection()) { connection.Open(); // The following line increments by one, but never commits the transaction, allowing it // to get disposed (which releases the session). await IncrementByOneAsync(connection, true); await RetryHelpers.ExecuteWithRetryAsync(async() => { using (var tx = await connection.BeginTransactionAsync()) { // Because Cloud Spanner does not have "read your writes" // to test any leaks, we must commit the transaction and then read it. await tx.CommitAsync(); } }); // The value should not be present in the table. using (var cmd = connection.CreateSelectCommand($"SELECT Int64Value FROM {_fixture.TableName} WHERE K=@k")) { cmd.Parameters.Add("k", SpannerDbType.String, _key); Assert.Equal(DBNull.Value, await cmd.ExecuteScalarAsync().ConfigureAwait(false)); } } }
public void AdapterUpdate() { RetryHelpers.RetryOnce(() => { using (var connection = _fixture.GetConnection()) { var adapter = new SpannerDataAdapter(connection, _fixture.TableName, "Key"); //Load var testDataSet = new DataSet(); adapter.Fill(testDataSet); //update, reload var newValue = Guid.NewGuid().ToString(); var oldKey = testDataSet.Tables[0].Rows[1]["Key"]; testDataSet.Tables[0].Rows[1]["StringValue"] = newValue; adapter.Update(testDataSet); testDataSet.Clear(); adapter.Fill(testDataSet); int i = 0; for (; i < testDataSet.Tables[0].Rows.Count; i++) { if (testDataSet.Tables[0].Rows[i]["Key"].Equals(oldKey)) { break; } } var row = testDataSet.Tables[0].Rows.Cast <DataRow>() .FirstOrDefault(r => r["Key"].Equals(oldKey)); Assert.NotNull(row); Assert.Equal(newValue, row["StringValue"]); } }); }
public void MultiTableWrite() { // For simplicity, use a new key so that this test is entirely self-contained. string key = IdGenerator.FromGuid(); RetryHelpers.ExecuteWithRetry(() => { using (var connection = _fixture.GetConnection()) { connection.Open(); using (var transaction = connection.BeginTransaction()) { using (var cmd1 = connection.CreateInsertCommand(_fixture.TableName)) { cmd1.Transaction = transaction; cmd1.Parameters.Add("K", SpannerDbType.String).Value = key; cmd1.Parameters.Add("StringValue", SpannerDbType.String).Value = "text"; cmd1.ExecuteNonQuery(); } using (var cmd2 = connection.CreateInsertCommand(_fixture.TableName2)) { cmd2.Transaction = transaction; cmd2.Parameters.Add("K", SpannerDbType.String).Value = key; cmd2.Parameters.Add("Int64Value", SpannerDbType.Int64).Value = 50; cmd2.ExecuteNonQuery(); } // Commit mutations from both commands, atomically. transaction.Commit(); } } }); // Read the values from both tables using (var connection = _fixture.GetConnection()) { using (var command = connection.CreateSelectCommand($"SELECT * FROM {_fixture.TableName} WHERE K=@Key")) { command.Parameters.Add("Key", SpannerDbType.String).Value = key; using (var reader = command.ExecuteReader()) { Assert.True(reader.Read()); Assert.Equal("text", reader["StringValue"]); Assert.False(reader.Read()); } } using (var command = connection.CreateSelectCommand($"SELECT * FROM {_fixture.TableName2} WHERE K=@Key")) { command.Parameters.Add("Key", SpannerDbType.String).Value = key; using (var reader = command.ExecuteReader()) { Assert.True(reader.Read()); Assert.Equal(50L, reader["Int64Value"]); Assert.False(reader.Read()); } } } }
/// <summary> /// Each test is able to use a different set of rows, varied by key value K. /// This method creates the rows with a random K and returns K. /// </summary> public string CreateTestRows([CallerMemberName] string testName = null) { string key = $"{testName} - {Guid.NewGuid()}"; Insert(0, false, false, false); Insert(1, true, false, false); Insert(2, false, true, false); Insert(3, false, false, true); Insert(4, true, true, true); void Insert(int value, bool update, bool delete, bool copy) { RetryHelpers.ExecuteWithRetry(() => { using (var connection = GetConnection()) { using (var command = connection.CreateInsertCommand(TableName)) { command.Parameters.Add("Key", SpannerDbType.String, key); command.Parameters.Add("OriginalValue", SpannerDbType.Int64, value); command.Parameters.Add("Value", SpannerDbType.Int64, value); command.Parameters.Add("UpdateMe", SpannerDbType.Bool, update); command.Parameters.Add("DeleteMe", SpannerDbType.Bool, delete); command.Parameters.Add("CopyMe", SpannerDbType.Bool, copy); RetryHelpers.ExecuteWithRetry(() => command.ExecuteNonQuery()); } } }); } return(key); }
public void AdapterDeleteInsert() { RetryHelpers.RetryOnce(() => { using (var connection = _fixture.GetConnection()) { var adapter = new SpannerDataAdapter(connection, _fixture.TableName, "Key"); //Load var testDataSet = new DataSet(); adapter.Fill(testDataSet); var k0 = testDataSet.Tables[0].Rows[0]["Key"]; var stringValue0 = testDataSet.Tables[0].Rows[0]["StringValue"]; Assert.IsType <string>(k0); Assert.IsType <string>(stringValue0); //Delete, reload testDataSet.Tables[0].Rows[0].Delete(); adapter.Update(testDataSet); testDataSet.Clear(); adapter.Fill(testDataSet); Assert.Equal(_fixture.RowCount - 1, testDataSet.Tables[0].Rows.Count); //insert, reload var newRow = testDataSet.Tables[0].NewRow(); newRow["Key"] = k0; newRow["StringValue"] = stringValue0; testDataSet.Tables[0].Rows.Add(newRow); adapter.Update(testDataSet); testDataSet.Clear(); adapter.Fill(testDataSet); Assert.Equal(_fixture.RowCount, testDataSet.Tables[0].Rows.Count); } }); }
public void AdapterOverrideSelect() { RetryHelpers.RetryOnce(() => { using (var connection = _fixture.GetConnection()) { var adapter = new SpannerDataAdapter(connection, _fixture.TableName, "Key") { SelectCommand = connection.CreateSelectCommand( $"SELECT * FROM {_fixture.TableName} WHERE Key='k2'") }; //Load var testDataSet = new DataSet(); adapter.Fill(testDataSet); Assert.Equal(1, testDataSet.Tables[0].Rows.Count); //update, reload (update still works even with an overloaded selectcommand) string newValue = Guid.NewGuid().ToString(); testDataSet.Tables[0].Rows[0]["StringValue"] = newValue; adapter.Update(testDataSet); testDataSet.Clear(); adapter.Fill(testDataSet); Assert.Equal(newValue, testDataSet.Tables[0].Rows[0]["StringValue"]); } }); }
protected override void PopulateTable(bool fresh) { // If we're using an old table, assume that the data is okay. if (!fresh) { return; } using (var connection = GetConnection()) { connection.Open(); RetryHelpers.ExecuteWithRetry(() => { using (var tx = connection.BeginTransaction()) { var cmd = connection.CreateInsertCommand(TableName); var keyParameter = cmd.Parameters.Add("Key", SpannerDbType.String); var stringValueParameter = cmd.Parameters.Add("StringValue", SpannerDbType.String); var int64ValueParameter = cmd.Parameters.Add("Int64Value", SpannerDbType.Int64); cmd.Transaction = tx; for (var i = 0; i < RowCount; i++) { keyParameter.Value = "k" + i; stringValueParameter.Value = "v" + i; int64ValueParameter.Value = i; cmd.ExecuteNonQuery(); } tx.Commit(); } }); } }
public async Task BaselineTest(SharedFxConfig config) { var previousVersion = TestData.GetPreviousAspNetCoreReleaseVersion(); var url = new Uri($"https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/" + previousVersion + "/aspnetcore-runtime-internal-" + previousVersion + "-win-x64.zip"); var zipName = "assemblies.zip"; var nugetAssemblyVersions = new Dictionary <string, Version>(); var dir = TestData.GetTestDataValue($"RuntimeAssetsOutputPath:{config.Name}"); using (var testClient = new WebClient()) { var reporter = new ConsoleReporter(PhysicalConsole.Singleton); await RetryHelpers.RetryAsync(async() => await testClient.DownloadFileTaskAsync(url, zipName), reporter); } var zipPath = Path.Combine(AppContext.BaseDirectory, zipName); var tempDirectoryPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); try { Directory.CreateDirectory(tempDirectoryPath); ZipFile.ExtractToDirectory(zipPath, tempDirectoryPath); var nugetAssembliesPath = Path.Combine(tempDirectoryPath, "shared", config.Name, previousVersion); var files = Directory.GetFiles(nugetAssembliesPath, "*.dll"); foreach (var file in files) { try { var assemblyVersion = AssemblyName.GetAssemblyName(file).Version; var dllName = Path.GetFileName(file); nugetAssemblyVersions.Add(dllName, assemblyVersion); } catch (BadImageFormatException) { } } files = Directory.GetFiles(dir, "*.dll"); Assert.All(files, file => { try { var localAssemblyVersion = AssemblyName.GetAssemblyName(file).Version; var dllName = Path.GetFileName(file); Assert.Contains(dllName, nugetAssemblyVersions.Keys); Assert.InRange(localAssemblyVersion.CompareTo(nugetAssemblyVersions[dllName]), 0, int.MaxValue); } catch (BadImageFormatException) { } }); } finally { Directory.Delete(tempDirectoryPath, true); } }
protected override void PopulateTable(bool fresh) { // Assume old data is still valid if (!fresh) { return; } const int PartitionSize = 5000; using (var connection = GetConnection()) { connection.Open(); for (var i = 0; i < NumPartitionReadRows / PartitionSize; i++) { RetryHelpers.RetryOnce(() => { using (var tx = connection.BeginTransaction()) { using (var cmd = connection.CreateInsertCommand(TableName)) { var idParameter = cmd.Parameters.Add("OrderId", SpannerDbType.String); var dateParameter = cmd.Parameters.Add("OrderDate", SpannerDbType.Timestamp); var productParameter = cmd.Parameters.Add("Product", SpannerDbType.String); cmd.Transaction = tx; DateTime now = DateTime.UtcNow; for (var x = 1; x < PartitionSize; x++) { idParameter.Value = IdGenerator.FromGuid(); dateParameter.Value = now.AddDays(-x); productParameter.Value = $"Widget#{x}"; cmd.ExecuteNonQuery(); } tx.Commit(); } } }); } } }
protected override void PopulateTable(bool fresh) { // If we're using an old table, assume that the data is okay. if (!fresh) { return; } using (var connection = GetConnection()) { connection.Open(); Assert.True(connection.IsOpen); RetryHelpers.ExecuteWithRetry(() => { using (var tx = connection.BeginTransaction()) { var cmd = connection.CreateInsertCommand(TableName); var keyParameter = cmd.Parameters.Add("Key", SpannerDbType.String); var valueParameter = cmd.Parameters.Add("StringValue", SpannerDbType.String); cmd.Transaction = tx; for (var i = 0; i < RowCount - 1; ++i) { keyParameter.Value = "k" + i; valueParameter.Value = "v" + i; cmd.ExecuteNonQuery(); } // And one extra row, with a null value. keyParameter.Value = "kNull"; valueParameter.Value = DBNull.Value; cmd.ExecuteNonQuery(); tx.Commit(); } }); } }
public async Task ReturnCommitStats() { Skip.If(_fixture.RunningOnEmulator, "Emulator does not yet support CommitStats"); CommitStatsCapturerLogger logger = new CommitStatsCapturerLogger(); string key = IdGenerator.FromGuid(); await RetryHelpers.ExecuteWithRetryAsync(async() => { using (var connection = _fixture.GetConnection(logger)) { await connection.OpenAsync(); using (var transaction = connection.BeginTransaction()) { transaction.LogCommitStats = true; using (var cmd1 = connection.CreateInsertCommand(_fixture.TableName)) { cmd1.Transaction = transaction; cmd1.Parameters.Add("K", SpannerDbType.String).Value = key; cmd1.Parameters.Add("StringValue", SpannerDbType.String).Value = "text"; await cmd1.ExecuteNonQueryAsync(); } using (var cmd2 = connection.CreateInsertCommand(_fixture.TableName2)) { cmd2.Transaction = transaction; cmd2.Parameters.Add("K", SpannerDbType.String).Value = key; cmd2.Parameters.Add("Int64Value", SpannerDbType.Int64).Value = 50; await cmd2.ExecuteNonQueryAsync(); } await transaction.CommitAsync(); // MutationCount == 4, as we inserted 2 rows with 2 columns each. Assert.Equal(4, logger.LastCommitResponse?.CommitStats?.MutationCount); } } }); }
public async Task TestChunking() { Logger.DefaultLogger.Info(() => $"Seed={_seed}"); var rowsRead = 0; int rowsToWrite = _random.Next(1, 6); using (var connection = _fixture.GetConnection()) { await connection.OpenAsync(); await RetryHelpers.RetryOnceAsync(async() => { using (var tx = await connection.BeginTransactionAsync()) { using (var cmd = connection.CreateInsertCommand( _fixture.TableName, new SpannerParameterCollection { new SpannerParameter("K", SpannerDbType.String), new SpannerParameter("StringValue", SpannerDbType.String), new SpannerParameter("StringArrayValue", SpannerDbType.ArrayOf(SpannerDbType.String)), new SpannerParameter("BytesValue", SpannerDbType.Bytes), new SpannerParameter("BytesArrayValue", SpannerDbType.ArrayOf(SpannerDbType.Bytes)) })) { cmd.Transaction = tx; //write 1-5 rows for (var i = 0; i < rowsToWrite; i++) { await InsertRowAsync(cmd); } await tx.CommitAsync(); } } }); using (var readCmd = connection.CreateSelectCommand($"SELECT * FROM {_fixture.TableName}")) { using (var reader = await readCmd.ExecuteReaderAsync()) { var keySet = new HashSet <string>(); while (await reader.ReadAsync()) { var k = reader.GetFieldValue <string>("K"); if (!_addedKeys.Contains(k)) { continue; // this key is from a previous test run. } rowsRead++; Assert.True(keySet.Add(k)); Assert.Equal(_stringValues[k], reader.GetFieldValue <string>("StringValue")); Assert.Equal(_stringArrayValues[k], reader.GetFieldValue <string[]>("StringArrayValue")); Assert.Equal(_bytesValues[k], reader.GetFieldValue <byte[]>("BytesValue")); Assert.Equal(_bytesArrayValues[k], reader.GetFieldValue <byte[][]>("BytesArrayValue")); } } } } Assert.Equal(rowsToWrite, rowsRead); }