blob: aa32153acc5f2ff3e40dd774f369ef4b4aa06613 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using Apache.Arrow.Adbc.Drivers.BigQuery;
using Apache.Arrow.Ipc;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace Apache.Arrow.Adbc.Tests.Drivers.BigQuery
{
[TestCaseOrderer("Apache.Arrow.Adbc.Tests.Xunit.TestOrderer", "Apache.Arrow.Adbc.Tests")]
public class StatementTests
{
BigQueryTestConfiguration _testConfiguration;
readonly List<BigQueryTestEnvironment> _environments;
readonly Dictionary<string, AdbcConnection> _configuredConnections = new Dictionary<string, AdbcConnection>();
readonly ITestOutputHelper? _outputHelper;
public StatementTests(ITestOutputHelper? outputHelper)
{
Skip.IfNot(Utils.CanExecuteTestConfig(BigQueryTestingUtils.BIGQUERY_TEST_CONFIG_VARIABLE));
_testConfiguration = MultiEnvironmentTestUtils.LoadMultiEnvironmentTestConfiguration<BigQueryTestConfiguration>(BigQueryTestingUtils.BIGQUERY_TEST_CONFIG_VARIABLE);
_environments = MultiEnvironmentTestUtils.GetTestEnvironments<BigQueryTestEnvironment>(_testConfiguration);
_outputHelper = outputHelper;
foreach (BigQueryTestEnvironment environment in _environments)
{
AdbcConnection connection = BigQueryTestingUtils.GetBigQueryAdbcConnection(environment);
_configuredConnections.Add(environment.Name!, connection);
}
}
[Fact]
public void CanSetStatementOption()
{
foreach (BigQueryTestEnvironment environment in _environments)
{
// ensure the value isn't already set
Assert.False(environment.AllowLargeResults);
AdbcConnection adbcConnection = BigQueryTestingUtils.GetBigQueryAdbcConnection(environment);
AdbcStatement statement = adbcConnection.CreateStatement();
statement.SetOption(BigQueryParameters.AllowLargeResults, "true");
// BigQuery is currently on ADBC 1.0, so it doesn't have the GetOption interface. Therefore, use reflection to validate the value is set correctly.
const BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
IReadOnlyDictionary<string, string>? options = statement.GetType().GetProperty("Options", bindingAttr)!.GetValue(statement) as IReadOnlyDictionary<string, string>;
Assert.True(options != null);
Assert.True(options[BigQueryParameters.AllowLargeResults] == "true");
}
}
[Fact]
public async Task CanCancelStatement()
{
foreach (BigQueryTestEnvironment environment in _environments)
{
AdbcConnection adbcConnection = GetAdbcConnection(environment.Name);
AdbcStatement statement = adbcConnection.CreateStatement();
// Execute the query/cancel multiple times to validate consistent behavior
const int iterations = 3;
for (int i = 0; i < iterations; i++)
{
_outputHelper?.WriteLine($"Iteration {i + 1} of {iterations}");
// Generate unique column names so query will not be served from cache
string columnName1 = Guid.NewGuid().ToString("N");
string columnName2 = Guid.NewGuid().ToString("N");
statement.SqlQuery = $"SELECT GENERATE_ARRAY(`{columnName2}`, 10000) AS `{columnName1}` FROM UNNEST(GENERATE_ARRAY(0, 100000)) AS `{columnName2}`";
_outputHelper?.WriteLine($"Query: {statement.SqlQuery}");
// Expect this to take about 10 seconds without cancellation
Task<QueryResult> queryTask = Task.Run(statement.ExecuteQuery);
await Task.Yield();
await Task.Delay(3000);
statement.Cancel();
try
{
QueryResult queryResult = await queryTask;
Assert.Fail("Expecting OperationCanceledException to be thrown.");
}
catch (Exception ex) when (ex is OperationCanceledException)
{
_outputHelper?.WriteLine($"Received expected OperationCanceledException: {ex.Message}");
}
catch (Exception ex) when (ex is not FailException)
{
Assert.Fail($"Expecting OperationCanceledException to be thrown. Instead, received {ex.GetType().Name}: {ex.Message}");
}
}
}
}
[Fact]
public async Task CanCancelStreamAndDisposeStatement()
{
foreach (BigQueryTestEnvironment environment in _environments)
{
using AdbcConnection adbcConnection = GetAdbcConnection(environment.Name);
AdbcStatement statement = adbcConnection.CreateStatement();
// Execute the query/cancel multiple times to validate consistent behavior
const int iterations = 3;
QueryResult[] results = new QueryResult[iterations];
for (int i = 0; i < iterations; i++)
{
_outputHelper?.WriteLine($"Iteration {i + 1} of {iterations}");
// Generate unique column names so query will not be served from cache
string columnName1 = Guid.NewGuid().ToString("N");
string columnName2 = Guid.NewGuid().ToString("N");
statement.SqlQuery = $"SELECT `{columnName2}` AS `{columnName1}` FROM UNNEST(GENERATE_ARRAY(1, 100)) AS `{columnName2}`";
_outputHelper?.WriteLine($"Query: {statement.SqlQuery}");
// Expect this to take about 10 seconds without cancellation
results[i] = statement.ExecuteQuery();
}
statement.Cancel();
statement.Dispose();
for (int index = 0; index < iterations; index++)
{
try
{
QueryResult queryResult = results[index];
using IArrowArrayStream? stream = queryResult.Stream;
Assert.NotNull(stream);
RecordBatch batch = await stream.ReadNextRecordBatchAsync();
Assert.Fail("Expecting OperationCanceledException to be thrown.");
}
catch (Exception ex) when (BigQueryUtils.ContainsException(ex, out OperationCanceledException? _))
{
_outputHelper?.WriteLine($"Received expected OperationCanceledException: {ex.Message}");
}
catch (Exception ex) when (ex is not FailException)
{
Assert.Fail($"Expecting OperationCanceledException to be thrown. Instead, received {ex.GetType().Name}: {ex.Message}");
}
}
}
}
[Fact]
public async Task CanCancelStreamFromStatement()
{
foreach (BigQueryTestEnvironment environment in _environments)
{
using AdbcConnection adbcConnection = GetAdbcConnection(environment.Name);
using AdbcStatement statement = adbcConnection.CreateStatement();
// Execute the query/cancel multiple times to validate consistent behavior
const int iterations = 3;
QueryResult[] results = new QueryResult[iterations];
for (int i = 0; i < iterations; i++)
{
_outputHelper?.WriteLine($"Iteration {i + 1} of {iterations}");
// Generate unique column names so query will not be served from cache
string columnName1 = Guid.NewGuid().ToString("N");
string columnName2 = Guid.NewGuid().ToString("N");
statement.SqlQuery = $"SELECT `{columnName2}` AS `{columnName1}` FROM UNNEST(GENERATE_ARRAY(1, 100)) AS `{columnName2}`";
_outputHelper?.WriteLine($"Query: {statement.SqlQuery}");
// Expect this to take about 10 seconds without cancellation
results[i] = statement.ExecuteQuery();
}
statement.Cancel();
for (int index = 0; index < iterations; index++)
{
try
{
QueryResult queryResult = results[index];
using IArrowArrayStream? stream = queryResult.Stream;
Assert.NotNull(stream);
RecordBatch batch = await stream.ReadNextRecordBatchAsync();
Assert.Fail("Expecting OperationCanceledException to be thrown.");
}
catch (Exception ex) when (BigQueryUtils.ContainsException(ex, out OperationCanceledException? _))
{
_outputHelper?.WriteLine($"Received expected OperationCanceledException: {ex.Message}");
}
catch (Exception ex) when (ex is not FailException)
{
Assert.Fail($"Expecting OperationCanceledException to be thrown. Instead, received {ex.GetType().Name}: {ex.Message}");
}
}
}
}
private AdbcConnection GetAdbcConnection(string? environmentName)
{
if (string.IsNullOrEmpty(environmentName))
{
throw new ArgumentNullException(nameof(environmentName));
}
return _configuredConnections[environmentName!];
}
}
}