public async Task InitializeAsync() { _harness = await new MiniKuduClusterBuilder().BuildHarnessAsync(); var options = _harness.CreateClientBuilder().BuildOptions(); var securityContext = new SecurityContext(); var systemClock = new SystemClock(); var connectionFactory = new KuduConnectionFactory( options, securityContext, NullLoggerFactory.Instance); _testConnectionFactory = new TestConnectionFactory(connectionFactory); _client = new KuduClient( options, securityContext, _testConnectionFactory, systemClock, NullLoggerFactory.Instance); var builder = ClientTestUtil.GetBasicSchema() .SetTableName("chaos_test_table") .SetNumReplicas(3) .CreateBasicRangePartition(); _table = await _client.CreateTableAsync(builder); }
public async Task TestSubmitWriteOpAfterCommit() { await using var harness = await new MiniKuduClusterBuilder() .AddMasterServerFlag("--txn_manager_enabled") .AddTabletServerFlag("--enable_txn_system_client_init=true") .BuildHarnessAsync(); await using var client = harness.CreateClient(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestSubmitWriteOpAfterCommit)) .AddHashPartitions(2, "key"); var table = await client.CreateTableAsync(builder); using var transaction = await client.NewTransactionAsync(); int key = 0; var insert1 = ClientTestUtil.CreateBasicSchemaInsert(table, key++); await transaction.WriteAsync(new[] { insert1 }); await transaction.CommitAsync(); await transaction.WaitForCommitAsync(); var insert2 = ClientTestUtil.CreateBasicSchemaInsert(table, key); var exception = await Assert.ThrowsAsync <NonRecoverableException>( async() => await transaction.WriteAsync(new[] { insert2 })); Assert.Matches(".* transaction ID .* not open: COMMITTED", exception.Message); }
public async Task TestScanTokenRequestsWithMetadata( bool includeTableMetadata, bool includeTabletMetadata) { var builder = ClientTestUtil.GetBasicSchema() .SetTableName(_tableName) .SetNumReplicas(3); var table = await _client.CreateTableAsync(builder); await ClientTestUtil.LoadDefaultTableAsync(_client, table, 1); var tokens = await _client.NewScanTokenBuilder(table) .IncludeTableMetadata(includeTableMetadata) .IncludeTabletMetadata(includeTabletMetadata) .BuildAsync(); var token = Assert.Single(tokens); // Use a new client to simulate hydrating in a new process. var newClient = _harness.CreateClient(); var scanBuilder = await newClient.NewScanBuilderFromTokenAsync(token.Serialize()); var scanner = scanBuilder.Build(); Assert.Equal(1, await scanner.CountAsync()); }
public async Task TestCount() { await using var miniCluster = await new MiniKuduClusterBuilder().BuildAsync(); await using var client = miniCluster.CreateClient(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestCount)) .AddHashPartitions(4, "key"); var table = await client.CreateTableAsync(builder); int numRows = 123; var rows = Enumerable.Range(0, numRows) .Select(i => ClientTestUtil.CreateBasicSchemaInsert(table, i)); await client.WriteAsync(rows); var scanner = client.NewScanBuilder(table) .SetEmptyProjection() .SetReadMode(ReadMode.ReadYourWrites) .Build(); long numScannedRows = await scanner.CountAsync(); Assert.Empty(scanner.ProjectionSchema.Columns); Assert.Equal(numRows, numScannedRows); }
public async Task TestDiffScanTokensConcurrentColumnRename() { var builder = ClientTestUtil.GetBasicSchema() .SetTableName(_tableName) .SetNumReplicas(1); var table = await _client.CreateTableAsync(builder); // Set up the table for a diff scan. int numRows = 20; long timestamp = await SetupTableForDiffScansAsync(table, numRows); // Since the diff scan interval is [start, end), increment the start timestamp // to exclude the last row inserted in the first group of ops, and increment the // end timestamp to include the last row deleted in the second group of ops. List <KuduScanToken> tokens = await _client.NewScanTokenBuilder(table) // TODO(KUDU-3146): Disable including the table metadata so the new column // name is retrieved when deserializing the scanner. .IncludeTableMetadata(false) .DiffScan(timestamp + 1, _client.LastPropagatedTimestamp + 1) .BuildAsync(); var token = Assert.Single(tokens); // Rename a column between when the token is created and when it is // rehydrated into a scanner await _client.AlterTableAsync(new AlterTableBuilder(table) .RenameColumn("column1_i", "column1_i_new")); var scanBuilder = await _client.NewScanBuilderFromTokenAsync(token); var scanner = scanBuilder.Build(); await CheckDiffScanResultsAsync(scanner, 3 *numRows / 4, numRows / 4); }
public async Task TestOpenScanWithDroppedPartition() { await using var miniCluster = await new MiniKuduClusterBuilder().BuildAsync(); await using var client = miniCluster.CreateClient(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName("TestOpenScanWithDroppedPartition") .CreateBasicRangePartition() .AddRangePartition((lower, upper) => { lower.SetInt32("key", 0); upper.SetInt32("key", 1000); }) .AddRangePartition((lower, upper) => { lower.SetInt32("key", 1000); upper.SetInt32("key", 2000); }); var table = await client.CreateTableAsync(builder); // Load rows into both partitions. int numRows = 1999; await ClientTestUtil.LoadDefaultTableAsync(client, table, numRows); // Scan the rows while dropping a partition. var scanner = client.NewScanBuilder(table) // Set a small batch size so the first scan doesn't read all the rows. .SetBatchSizeBytes(100) .SetReadMode(ReadMode.ReadYourWrites) .Build(); long rowsScanned = 0; int batchNum = 0; await foreach (var resultSet in scanner) { if (batchNum == 1) { // Drop the partition. await client.AlterTableAsync(new AlterTableBuilder(table) .DropRangePartition((lower, upper) => { lower.SetInt32("key", 0); upper.SetInt32("key", 1000); })); // Give time for the background drop operations. await Task.Delay(1000); // TODO: Verify the partition was dropped. } rowsScanned += resultSet.Count; batchNum++; } Assert.True(batchNum > 1); Assert.Equal(numRows, rowsScanned); }
public async Task TestInsertIgnore() { var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestInsertIgnore)); var table = await _client.CreateTableAsync(builder); // Test insert ignore implements normal insert. var insert = ClientTestUtil.CreateBasicSchemaInsertIgnore(table, 1); await _client.WriteAsync(new[] { insert }); var rowStrings = await ClientTestUtil.ScanTableToStringsAsync(_client, table); var rowString = Assert.Single(rowStrings); Assert.Equal( "INT32 key=1, INT32 column1_i=2, INT32 column2_i=3, " + "STRING column3_s=a string, BOOL column4_b=True", rowString); // Test insert ignore does not return a row error. await _client.WriteAsync(new[] { insert }); rowStrings = await ClientTestUtil.ScanTableToStringsAsync(_client, table); rowString = Assert.Single(rowStrings); Assert.Equal( "INT32 key=1, INT32 column1_i=2, INT32 column2_i=3, " + "STRING column3_s=a string, BOOL column4_b=True", rowString); }
public async Task TestInsertAfterInsertIgnoreHasRowError() { var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestInsertAfterInsertIgnoreHasRowError)); var table = await _client.CreateTableAsync(builder); var rows = new[] { ClientTestUtil.CreateBasicSchemaInsertIgnore(table, 1), ClientTestUtil.CreateBasicSchemaInsert(table, 1) }; var exception = await Assert.ThrowsAsync <KuduWriteException>( () => _client.WriteAsync(rows)); var rowError = Assert.Single(exception.PerRowErrors); Assert.True(rowError.IsAlreadyPresent); var rowStrings = await ClientTestUtil.ScanTableToStringsAsync(_client, table); var rowString = Assert.Single(rowStrings); Assert.Equal( "INT32 key=1, INT32 column1_i=2, INT32 column2_i=3, " + "STRING column3_s=a string, BOOL column4_b=True", rowString); }
public async Task TestTimeoutEvenWhenServerHangs() { await using var harness = await new MiniKuduClusterBuilder() .AddTabletServerFlag("--scanner_inject_latency_on_each_batch_ms=200000") .BuildHarnessAsync(); await using var client = harness.CreateClient(); var tableBuilder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestTimeoutEvenWhenServerHangs)); var table = await client.CreateTableAsync(tableBuilder); var row = ClientTestUtil.CreateBasicSchemaInsert(table, 1); await client.WriteAsync(new[] { row }); var scanner = client.NewScanBuilder(table).Build(); // Scan with a short timeout. var timeout = TimeSpan.FromSeconds(1); using var cts = new CancellationTokenSource(timeout); // The server will not respond for the lifetime of the test, so we // expect the operation to time out. await Assert.ThrowsAsync <OperationCanceledException>( async() => await scanner.CountAsync(cts.Token)); }
public async Task TestIterable() { await using var miniCluster = await new MiniKuduClusterBuilder().BuildAsync(); await using var client = miniCluster.CreateClient(); await using var session = client.NewSession(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName("TestIterable") .CreateBasicRangePartition(); var table = await client.CreateTableAsync(builder); IDictionary <int, PartialRow> inserts = new Dictionary <int, PartialRow>(); int numRows = 10; for (int i = 0; i < numRows; i++) { var insert = table.NewInsert(); _generator.RandomizeRow(insert); inserts.TryAdd(insert.GetInt32(0), insert); await session.EnqueueAsync(insert); } await session.FlushAsync(); var scanner = client.NewScanBuilder(table) .SetReadMode(ReadMode.ReadYourWrites) .SetReplicaSelection(ReplicaSelection.LeaderOnly) .Build(); await foreach (var resultSet in scanner) { foreach (var row in resultSet) { var key = row.GetInt32(0); var insert = Assert.Contains(key, inserts); Assert.Equal(insert.GetInt32(1), row.GetInt32(1)); Assert.Equal(insert.GetInt32(2), row.GetInt32(2)); if (insert.IsNull(3)) { Assert.True(row.IsNull(3)); } else { Assert.Equal(insert.GetString(3), row.GetString(3)); } Assert.Equal(insert.GetBool(4), row.GetBool(4)); inserts.Remove(key); } } Assert.Empty(inserts); }
public async Task TestTxnKeepaliveSwitchesToOtherTxnManager() { await using var harness = await new MiniKuduClusterBuilder() .AddMasterServerFlag("--txn_manager_enabled") // Set Raft heartbeat interval short for faster test runtime: speed up // leader failure detection and new leader election. .AddMasterServerFlag("--raft_heartbeat_interval_ms=100") // The txn keepalive interval should be long enough to accommodate Raft // leader failure detection and election. .AddTabletServerFlag("--txn_keepalive_interval_ms=1000") .AddTabletServerFlag("--txn_staleness_tracker_interval_ms=250") .AddTabletServerFlag("--enable_txn_system_client_init=true") .BuildHarnessAsync(); await using var client = harness.CreateClient(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestTxnKeepaliveSwitchesToOtherTxnManager)) .AddHashPartitions(2, "key"); var table = await client.CreateTableAsync(builder); using var transaction = await client.NewTransactionAsync(); var insert = ClientTestUtil.CreateBasicSchemaInsert(table, 0); await transaction.WriteAsync(new[] { insert }); await harness.KillLeaderMasterServerAsync(); // Wait for two keepalive intervals to make sure the backend got a chance // to automatically abort the transaction if not receiving txn keepalive // messages. await Task.Delay(2 * 1000); // It should be possible to commit the transaction. This is to verify that // // * the client eventually starts sending txn keepalive messages to other // TxnManager instance (the original was hosted by former leader master // which is no longer available), so the backend doesn't abort the // transaction automatically due to not receiving keepalive messages // // * the client switches to the new TxnManager for other txn-related // operations as well await transaction.CommitAsync(); await transaction.WaitForCommitAsync(); // An extra sanity check: read back the rows written into the table in the // context of the transaction. var scanner = client.NewScanBuilder(table) .SetReadMode(ReadMode.ReadYourWrites) .SetReplicaSelection(ReplicaSelection.LeaderOnly) .Build(); Assert.Equal(1, await scanner.CountAsync()); }
public async Task TestPropagateTxnCommitTimestamp() { await using var harness = await new MiniKuduClusterBuilder() .AddMasterServerFlag("--txn_manager_enabled") // Inject latency to have a chance spotting the transaction in the // FINALIZE_IN_PROGRESS state and make KuduTransaction.WaitForCommitAsync() // have to poll multiple times. .AddTabletServerFlag("--txn_status_manager_inject_latency_finalize_commit_ms=250") .AddTabletServerFlag("--enable_txn_system_client_init=true") .BuildHarnessAsync(); await using var client = harness.CreateClient(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestPropagateTxnCommitTimestamp)) .AddHashPartitions(8, "key"); var table = await client.CreateTableAsync(builder); // Make sure the commit timestamp for a transaction is propagated to the // client upon committing a transaction. using (var transaction = await client.NewTransactionAsync()) { // Insert many rows: the goal is to get at least one row inserted into // every tablet of the hash-partitioned test table, so every tablet would // be a participant in the transaction, and most likely every tablet // server would be involved. var inserts = Enumerable .Range(0, 128) .Select(key => ClientTestUtil.CreateBasicSchemaInsert(table, key)); await transaction.WriteAsync(inserts); await CommitAndVerifyTransactionAsync(client, transaction); } // Make sure the commit timestamp for a transaction is propagated to the // client upon committing a transaction (using a session). using (var transaction = await client.NewTransactionAsync()) { await using var session = transaction.NewSession(); // Insert many rows: the goal is to get at least one row inserted into // every tablet of the hash-partitioned test table, so every tablet would // be a participant in the transaction, and most likely every tablet // server would be involved. for (int key = 128; key < 256; key++) { var insert = ClientTestUtil.CreateBasicSchemaInsert(table, key); await session.EnqueueAsync(insert); } await session.FlushAsync(); await CommitAndVerifyTransactionAsync(client, transaction); } }
public async Task TestKuduRequireEncryption() { await using var harness = await new MiniKuduClusterBuilder().BuildHarnessAsync(); await using var client = harness.CreateClientBuilder() .SetEncryptionPolicy(EncryptionPolicy.Required) .Build(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestKuduRequireEncryption)); var table = await client.CreateTableAsync(builder); Assert.NotNull(table.TableId); }
public async Task TestSwitchToOtherTxnManagerInFlightCalls() { await using var harness = await new MiniKuduClusterBuilder() .AddMasterServerFlag("--txn_manager_enabled") // Set Raft heartbeat interval short for faster test runtime: speed up // leader failure detection and new leader election. .AddMasterServerFlag("--raft_heartbeat_interval_ms=100") .AddTabletServerFlag("--enable_txn_system_client_init=true") .BuildHarnessAsync(); await using var client = harness.CreateClient(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestSwitchToOtherTxnManagerInFlightCalls)) .AddHashPartitions(2, "key"); var table = await client.CreateTableAsync(builder); using var transaction = await client.NewTransactionAsync(); var insert = ClientTestUtil.CreateBasicSchemaInsert(table, 0); await transaction.WriteAsync(new[] { insert }); await harness.KillAllMasterServersAsync(); var startMastersTask = Task.Run(async() => { // Sleep for some time to allow the commit call // below issue RPCs to non-running TxnManangers. await Task.Delay(1000); await harness.StartAllMasterServersAsync(); }); // It should be possible to commit the transaction. await transaction.CommitAsync(); await transaction.WaitForCommitAsync(); await startMastersTask; // An extra sanity check: read back the rows written into the table in the // context of the transaction. var scanner = client.NewScanBuilder(table) .SetReadMode(ReadMode.ReadYourWrites) .SetReplicaSelection(ReplicaSelection.LeaderOnly) .Build(); Assert.Equal(1, await scanner.CountAsync()); }
public async Task TestGetTableStatistics() { await using var harness = await new MiniKuduClusterBuilder() .AddTabletServerFlag("--update_tablet_stats_interval_ms=200") .AddTabletServerFlag("--heartbeat_interval_ms=100") .BuildHarnessAsync(); await using var client = harness.CreateClient(); // Create a table. var builder = ClientTestUtil.GetBasicSchema().SetTableName(_tableName); var table = await client.CreateTableAsync(builder); // Insert some rows and test the statistics. var prevStatistics = new KuduTableStatistics(-1, -1); var currentStatistics = new KuduTableStatistics(-1, -1); var session = client.NewSession(); int num = 100; for (int i = 0; i < num; ++i) { // Get current table statistics. currentStatistics = await client.GetTableStatisticsAsync(_tableName); Assert.True(currentStatistics.OnDiskSize >= prevStatistics.OnDiskSize); Assert.True(currentStatistics.LiveRowCount >= prevStatistics.LiveRowCount); Assert.True(currentStatistics.LiveRowCount <= i + 1); prevStatistics = currentStatistics; // Insert row. var insert = ClientTestUtil.CreateBasicSchemaInsert(table, i); await session.EnqueueAsync(insert); await session.FlushAsync(); long numRows = await ClientTestUtil.CountRowsAsync(client, table); Assert.Equal(i + 1, numRows); } // Final accuracy test. // Wait for master to aggregate table statistics. await Task.Delay(200 * 6); currentStatistics = await client.GetTableStatisticsAsync(_tableName); Assert.True(currentStatistics.OnDiskSize >= prevStatistics.OnDiskSize); Assert.True(currentStatistics.LiveRowCount >= prevStatistics.LiveRowCount); Assert.Equal(num, currentStatistics.LiveRowCount); }
public async Task TestExceptionCallback() { int numCallbacks = 0; SessionExceptionContext sessionContext = null; var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestExceptionCallback)); var table = await _client.CreateTableAsync(builder); var row1 = ClientTestUtil.CreateBasicSchemaInsert(table, 1); var row2 = ClientTestUtil.CreateBasicSchemaInsert(table, 1); var sessionOptions = new KuduSessionOptions { ExceptionHandler = HandleSessionExceptionAsync }; await using var session = _client.NewSession(sessionOptions); await session.EnqueueAsync(row1); await session.FlushAsync(); await session.EnqueueAsync(row2); await session.FlushAsync(); ValueTask HandleSessionExceptionAsync(SessionExceptionContext context) { numCallbacks++; sessionContext = context; return(new ValueTask()); } Assert.Equal(1, numCallbacks); var errorRow = Assert.Single(sessionContext.Rows); Assert.Same(row2, errorRow); var exception = Assert.IsType <KuduWriteException>(sessionContext.Exception); var exceptionRow = Assert.Single(exception.PerRowErrors); Assert.True(exceptionRow.IsAlreadyPresent); }
public async Task TestKuduRequireAuthenticationInsecureCluster() { await using var harness = await new MiniKuduClusterBuilder().BuildHarnessAsync(); await using var client = harness.CreateClientBuilder() .RequireAuthentication(true) .Build(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestKuduRequireAuthenticationInsecureCluster)); var exception = await Assert.ThrowsAsync <NonRecoverableException>( () => client.CreateTableAsync(builder)); Assert.Contains( "Client requires authentication, but server does not have Kerberos enabled", exception.Message); }
public async Task TestAuthzTokensDuringElection() { await using var client = _harness.CreateClient(); await using var session = client.NewSession(); // Test sending various requests that require authorization. var builder = ClientTestUtil.GetBasicSchema() .SetTableName(_tableName) .CreateBasicRangePartition() .SetNumReplicas(1); var table = await client.CreateTableAsync(builder); // Restart the masters to trigger an election. await _harness.KillAllMasterServersAsync(); await _harness.StartAllMasterServersAsync(); int numReqs = 10; await InsertRowsAsync(session, table, 0, numReqs); await session.FlushAsync(); // Do the same for batches of inserts. await _harness.KillAllMasterServersAsync(); await _harness.StartAllMasterServersAsync(); await InsertRowsAsync(session, table, numReqs, numReqs); await session.FlushAsync(); // And for scans. await _harness.KillAllMasterServersAsync(); await _harness.StartAllMasterServersAsync(); for (int i = 0; i < numReqs; i++) { var numRows = await ClientTestUtil.CountRowsAsync(client, table); Assert.Equal(2 * numReqs, numRows); } }
public async Task TestScannerExpiration() { await using var miniCluster = await new MiniKuduClusterBuilder() .AddTabletServerFlag($"--scanner_ttl_ms={ShortScannerTtlMs}") .AddTabletServerFlag($"--scanner_gc_check_interval_us={ShortScannerGcUs}") .BuildAsync(); await using var client = miniCluster.CreateClient(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName("TestScannerExpiration") .AddHashPartitions(2, "key"); var table = await client.CreateTableAsync(builder); int numRows = 1000; var rows = Enumerable.Range(0, numRows) .Select(i => ClientTestUtil.CreateBasicSchemaInsert(table, i)); await client.WriteAsync(rows); var scanner = client.NewScanBuilder(table) .SetReadMode(ReadMode.ReadYourWrites) .SetReplicaSelection(ReplicaSelection.ClosestReplica) .SetBatchSizeBytes(100) // Use a small batch size so we get many batches. .Build(); var scanEnumerator = scanner.GetAsyncEnumerator(); // Initialize the scanner and verify we can read rows. Assert.True(await scanEnumerator.MoveNextAsync()); Assert.True(scanEnumerator.Current.Count > 0); // Wait for the scanner to time out. await Task.Delay(ShortScannerTtlMs * 2); var exception = await Assert.ThrowsAsync <NonRecoverableException>(async() => await scanEnumerator.MoveNextAsync()); Assert.Matches(".*Scanner .* not found.*", exception.Message); // Closing an expired scanner shouldn't throw an exception. await scanEnumerator.DisposeAsync(); }
public async Task TestFailover(bool restart) { await using var harness = await new MiniKuduClusterBuilder() .NumMasters(3) .NumTservers(3) .BuildHarnessAsync(); await using var client = harness.CreateClient(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName("LeaderFailoverTest") .CreateBasicRangePartition(); var table = await client.CreateTableAsync(builder); var rows = Enumerable.Range(0, 3) .Select(i => ClientTestUtil.CreateBasicSchemaInsert(table, i)); await client.WriteAsync(rows); // Make sure the rows are in there before messing things up. long numRows = await ClientTestUtil.CountRowsAsync(client, table); Assert.Equal(3, numRows); if (restart) { await harness.RestartLeaderMasterAsync(); } else { await harness.KillLeaderMasterServerAsync(); } var rows2 = Enumerable.Range(3, 3) .Select(i => ClientTestUtil.CreateBasicSchemaInsert(table, i)); await client.WriteAsync(rows2); long numRows2 = await ClientTestUtil.CountRowsAsync(client, table); Assert.Equal(6, numRows2); }
public async Task TestMasterLookupOverflow() { var tableName = "TestHandleTooBusy"; await using var harness = await new MiniKuduClusterBuilder() // Short queue to provoke overflow. .AddMasterServerFlag("--rpc_service_queue_length=1") // Low number of service threads, so things stay in the queue. .AddMasterServerFlag("--rpc_num_service_threads=3") // Inject latency so lookups process slowly. .AddMasterServerFlag("--master_inject_latency_on_tablet_lookups_ms=100") .BuildHarnessAsync(); await using var client1 = harness.CreateClient(); await client1.CreateTableAsync(ClientTestUtil.GetBasicSchema() .SetTableName(tableName)); var tasks = new List <Task>(); for (int i = 0; i < 10; i++) { var task = Task.Run(async() => { for (int j = 0; j < 5; j++) { await using var client = harness.CreateClient(); var table = await client.OpenTableAsync(tableName); for (int k = 0; k < 5; k++) { await client.GetTableLocationsAsync( table.TableId, Array.Empty <byte>(), 1); } } }); tasks.Add(task); } await Task.WhenAll(tasks); }
public async Task TestTxnSessionClose() { await using var harness = await new MiniKuduClusterBuilder() .AddMasterServerFlag("--txn_manager_enabled") .AddTabletServerFlag("--enable_txn_system_client_init=true") .BuildHarnessAsync(); await using var client = harness.CreateClient(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestTxnSessionClose)) .AddHashPartitions(2, "key"); var table = await client.CreateTableAsync(builder); // Open and close an empty transaction session. using (var transaction = await client.NewTransactionAsync()) { await using var session = transaction.NewSession(); } // Open new transaction, insert one row for a session, close the session // and then rollback the transaction. No rows should be persisted. using (var transaction = await client.NewTransactionAsync()) { await using var session = transaction.NewSession(); var insert = ClientTestUtil.CreateBasicSchemaInsert(table, 1); await session.EnqueueAsync(insert); await session.FlushAsync(); await transaction.RollbackAsync(); var scanner = client.NewScanBuilder(table) .SetReadMode(ReadMode.ReadYourWrites) .SetReplicaSelection(ReplicaSelection.LeaderOnly) .Build(); Assert.Equal(0, await scanner.CountAsync()); } }
public async Task TestScanTokensWithExtraPredicate() { int numRows = 100; int predicateIndex = 0; int predicateValue = 1; var builder = ClientTestUtil.GetBasicSchema() .SetTableName(_tableName) .CreateBasicRangePartition(); var table = await _client.CreateTableAsync(builder); await ClientTestUtil.LoadDefaultTableAsync(_client, table, numRows); var tokens = await _client.NewScanTokenBuilder(table).BuildAsync(); var columnSchema = table.Schema.GetColumn(predicateIndex); var predicate = KuduPredicate.NewComparisonPredicate( columnSchema, ComparisonOp.Equal, predicateValue); var resultKeys = new List <int>(); foreach (var token in tokens) { byte[] serialized = token.Serialize(); var scanBuilder = await _client.NewScanBuilderFromTokenAsync(serialized); var scanner = scanBuilder .AddPredicate(predicate) .Build(); await foreach (var resultSet in scanner) { foreach (var row in resultSet) { resultKeys.Add(row.GetInt32(predicateIndex)); } } } Assert.Collection(resultKeys, key => Assert.Equal(predicateValue, key)); }
public async Task TestKuduOptionalEncryption() { await using var harness = await new MiniKuduClusterBuilder() .AddMasterServerFlag("--rpc_encryption=disabled") .AddMasterServerFlag("--rpc_authentication=disabled") .AddTabletServerFlag("--rpc_encryption=disabled") .AddTabletServerFlag("--rpc_authentication=disabled") .BuildHarnessAsync(); await using var client = harness.CreateClientBuilder() .SetEncryptionPolicy(EncryptionPolicy.Optional) .Build(); var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestKuduOptionalEncryption)); var table = await client.CreateTableAsync(builder); Assert.NotNull(table.TableId); }
public async Task TestAlterChangeOwner() { var originalOwner = "alice"; var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestAlterChangeOwner)) .SetRangePartitionColumns("key") .SetOwner(originalOwner); var table = await _client.CreateTableAsync(builder); Assert.Equal(originalOwner, table.Owner); var newOwner = "bob"; await _client.AlterTableAsync(new AlterTableBuilder(table) .SetOwner(newOwner)); table = await _client.OpenTableAsync(table.TableName); Assert.Equal(newOwner, table.Owner); }
public async Task TestDeleteIgnore() { var builder = ClientTestUtil.GetBasicSchema() .SetTableName(nameof(TestDeleteIgnore)); var table = await _client.CreateTableAsync(builder); // Test delete ignore does not return a row error. var delete = ClientTestUtil.CreateBasicSchemaDeleteIgnore(table, 1); await _client.WriteAsync(new[] { delete }); var insert = ClientTestUtil.CreateBasicSchemaInsert(table, 1); await _client.WriteAsync(new[] { insert }); Assert.Single(await ClientTestUtil.ScanTableToStringsAsync(_client, table)); // Test delete ignore implements normal delete. await _client.WriteAsync(new[] { delete }); Assert.Empty(await ClientTestUtil.ScanTableToStringsAsync(_client, table)); }
public async Task TestScanTokensConcurrentColumnRename() { var builder = ClientTestUtil.GetBasicSchema() .SetTableName(_tableName) .SetNumReplicas(1); var oldColName = "column1_i"; var table = await _client.CreateTableAsync(builder); var tokens = await _client.NewScanTokenBuilder(table) // TODO(KUDU-3146): Disable including the table metadata so the new column // name is retrieved when deserializing the scanner. .IncludeTableMetadata(false) .BuildAsync(); var token = Assert.Single(tokens); // Rename a column. var newColName = "new-name"; await _client.AlterTableAsync(new AlterTableBuilder(table) .RenameColumn(oldColName, newColName)); var scanBuilder = await _client.NewScanBuilderFromTokenAsync(token); var scanner = scanBuilder.Build(); // TODO(KUDU-3146): Handle renaming a column between when the token // is rehydrated as a scanner and when the scanner first hits a replica. // Note that this is almost certainly a very short period of vulnerability. Assert.Equal(0, await scanner.CountAsync()); // Test that the old name cannot be used and the new name can be. var alteredSchema = scanner.ProjectionSchema; Assert.Throws <KeyNotFoundException>(() => alteredSchema.GetColumn(oldColName)); alteredSchema.GetColumn(newColName); }
public async Task TestMultipleSessions() { int numTasks = 60; var tasks = new List <Task>(numTasks); var builder = ClientTestUtil.GetBasicSchema() .SetTableName("TestMultipleSessions") .CreateBasicRangePartition(); var table = await _client.CreateTableAsync(builder); using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); var token = cts.Token; for (int i = 0; i < numTasks; i++) { var task = Task.Run(async() => { while (!token.IsCancellationRequested) { await using var session = _client.NewSession(); for (int j = 0; j < 100; j++) { var row = table.NewUpsert(); row.SetInt32(0, j); row.SetInt32(1, 12345); row.SetInt32(2, 3); row.SetNull(3); row.SetBool(4, false); await session.EnqueueAsync(row); } } }); tasks.Add(task); } await Task.WhenAll(tasks); }
public async Task TestScanTokensWithTableRename() { var builder = ClientTestUtil.GetBasicSchema() .SetTableName(_tableName) .SetNumReplicas(1); var table = await _client.CreateTableAsync(builder); var tokens = await _client.NewScanTokenBuilder(table).BuildAsync(); var token = Assert.Single(tokens); // Rename the table. await _client.AlterTableAsync(new AlterTableBuilder(table) .RenameTable($"{_tableName}-renamed")); var scanBuilder = await _client.NewScanBuilderFromTokenAsync(token); var scanner = scanBuilder.Build(); Assert.Equal(0, await scanner.CountAsync()); }
public async Task TestDimensionLabel() { await using var harness = await new MiniKuduClusterBuilder().BuildHarnessAsync(); await using var client = harness.CreateClient(); // Create a table with dimension label. var builder = ClientTestUtil.GetBasicSchema() .SetTableName(_tableName) .CreateBasicNonCoveredRangePartitions() .SetDimensionLabel("labelA"); var table = await client.CreateTableAsync(builder); // Add a range partition to the table with dimension label. await client.AlterTableAsync(new AlterTableBuilder(table) .AddRangePartition((lower, upper) => { lower.SetInt32("key", 300); upper.SetInt32("key", 400); }, "labelB", RangePartitionBound.Inclusive, RangePartitionBound.Exclusive)); var tablets = await client.GetTableLocationsAsync(table.TableId, null, 100); var dimensionMap = tablets .SelectMany(t => t.Replicas) .GroupBy(r => r.DimensionLabel) .OrderBy(g => g.Key); Assert.Collection(dimensionMap, d => { Assert.Equal("labelA", d.Key); Assert.Equal(9, d.Count()); }, d => { Assert.Equal("labelB", d.Key); Assert.Equal(3, d.Count()); }); }