Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions .github/workflows/ruby_asan_on_ubuntu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Ubuntu

on:
push:
branches:
- main
pull_request:
types:
- opened
- synchronize
- reopened

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby: ['asan']
duckdb: ['1.1.3', '1.1.1', '1.2.0']

steps:
- uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}

- name: duckdb cache
id: duckdb-cache
uses: actions/cache@v4
with:
path: duckdb-v${{ matrix.duckdb }}
key: ${{ runner.os }}-duckdb-v${{ matrix.duckdb }}

- name: Build duckdb ${{ matrix.duckdb }}
env:
DUCKDB_VERSION: ${{ matrix.duckdb }}
if: steps.duckdb-cache.outputs.cache-hit != 'true'
run: |
git clone -b v$DUCKDB_VERSION https://github.com/cwida/duckdb.git duckdb-tmp-v$DUCKDB_VERSION
cd duckdb-tmp-v$DUCKDB_VERSION && make && cd ..
rm -rf duckdb-v$DUCKDB_VERSION
mkdir -p duckdb-v$DUCKDB_VERSION/build/release/src duckdb-v$DUCKDB_VERSION/src
cp -rip duckdb-tmp-v$DUCKDB_VERSION/build/release/src/*.so duckdb-v$DUCKDB_VERSION/build/release/src
cp -rip duckdb-tmp-v$DUCKDB_VERSION/src/include duckdb-v$DUCKDB_VERSION/src/

- name: bundle install with Ruby ${{ matrix.ruby }}
env:
DUCKDB_VERSION: ${{ matrix.duckdb }}
run: |
bundle install --jobs 4 --retry 3

- name: Build test with DUCKDB_API_NO_DEPRECATED and Ruby ${{ matrix.ruby }}
env:
DUCKDB_VERSION: ${{ matrix.duckdb }}
run: |
env DUCKDB_API_NO_DEPRECATED=1 bundle exec rake build -- --with-duckdb-include=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/src/include --with-duckdb-lib=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/build/release/src/
bundle exec rake clean

- name: Build with Ruby ${{ matrix.ruby }}
env:
DUCKDB_VERSION: ${{ matrix.duckdb }}
run: |
bundle exec rake build -- --with-duckdb-include=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/src/include --with-duckdb-lib=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/build/release/src/

- name: test with Ruby ${{ matrix.ruby }}
env:
DUCKDB_VERSION: ${{ matrix.duckdb }}
run: |
env RUBYOPT=-W:deprecated ASAN_TEST=1 bundle exec ruby -Ilib test/duckdb_test/asan_test.rb
2 changes: 1 addition & 1 deletion ext/duckdb/database.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ static const rb_data_type_t database_data_type = {
};

static void close_database(rubyDuckDB *p) {
duckdb_close(&(p->db));
if (p->db) duckdb_close(&(p->db));
}

static void deallocate(void * ctx) {
Expand Down
11 changes: 9 additions & 2 deletions test/duckdb_test/appender_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def setup
end

def safe_drop_table
@con.execute("DROP TABLE #{table};")
@con.execute("DROP TABLE IF EXISTS #{table};")
rescue DuckDB::Error
# ignore DuckDB::Error
end
Expand Down Expand Up @@ -49,8 +49,12 @@ def test_s_new_with_schema
@con.execute('CREATE SCHEMA a; CREATE TABLE a.b (id INT);')
appender = DuckDB::Appender.new(@con, 'a', 'b')
assert_instance_of(DuckDB::Appender, appender)
end

assert_raises(DuckDB::Error) { appender = DuckDB::Appender.new(@con, 'b', 'b') }
def test_s_new_with_invalid_schema
skip('test with ASAN') if ENV['ASAN_TEST'] == '1'
@con.execute('CREATE SCHEMA a; CREATE TABLE a.b (id INT);')
assert_raises(DuckDB::Error) { DuckDB::Appender.new(@con, 'b', 'b') }
end

def sub_test_append_column2(method, type, values:, expected:)
Expand Down Expand Up @@ -103,6 +107,7 @@ def test_flush
end

def test_flush_with_exception
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'
appender = create_appender('col BOOLEAN NOT NULL')
appender
.append_null
Expand All @@ -119,6 +124,7 @@ def test_end_row
end

def test_end_row_with_exception
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'
appender = create_appender('col BOOLEAN')
exception = assert_raises(DuckDB::Error) { appender.end_row }
assert_match(/Call to EndRow/, exception.message)
Expand All @@ -133,6 +139,7 @@ def test_close
end

def test_close_with_exception
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'
appender = create_appender('col BOOLEAN NOT NULL')
appender
.append_null
Expand Down
6 changes: 6 additions & 0 deletions test/duckdb_test/asan_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require 'duckdb'
begin
DuckDB::Database.open('not_exist_dir/not_exist_file')
rescue
puts "Error: #{$!}"
end
5 changes: 5 additions & 0 deletions test/duckdb_test/config_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,18 @@ def test_s_key_descriptions
def test_set_config
config = DuckDB::Config.new
assert_instance_of(DuckDB::Config, config.set_config('access_mode', 'READ_ONLY'))
end

def test_set_config_with_exception
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'
config = DuckDB::Config.new
assert_raises(DuckDB::Error) do
config.set_config('access_mode', 'INVALID_VALUE')
end
end

def test_set_invalid_option
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'
config = DuckDB::Config.new
assert_instance_of(DuckDB::Config, config.set_config('aaa_invalid_option', 'READ_ONLY'))
assert_raises(DuckDB::Error) do
Expand Down
1 change: 1 addition & 0 deletions test/duckdb_test/connection_execute_multiple_sql_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def setup
end

def test_multiple_sql
skip('test with ASAN') if ENV['ASAN_TEST'] == '1'
exception = assert_raises(DuckDB::Error) do
@con.execute('CREATE TABLE test (v VARCHAR); CREATE TABLE test (v VARCHAR); SELECT 42;')
end
Expand Down
31 changes: 20 additions & 11 deletions test/duckdb_test/connection_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,22 @@ def test_query_with_valid_hash_params
assert_equal('a', r.each.first[1])
end

def test_query_with_invalid_params
assert_raises(DuckDB::Error) { @con.query('foo', 'bar') }

assert_raises(ArgumentError) { @con.query }

assert_raises(TypeError) { @con.query(1) }
def test_query_with_invalid_params_and_raise_duckdb_error
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'

assert_raises(DuckDB::Error) { @con.query('foo', 'bar') }
assert_raises(DuckDB::Error) do
invalid_sql = 'CREATE TABLE table1 ('
@con.query(invalid_sql)
end
end

def test_query_with_invalid_params
assert_raises(ArgumentError) { @con.query }

assert_raises(TypeError) { @con.query(1) }
end

def test_async_query
pending_result = @con.async_query('CREATE TABLE table1 (id INTEGER)')
assert_instance_of(DuckDB::PendingResult, pending_result)
Expand Down Expand Up @@ -79,6 +82,7 @@ def test_async_query_with_valid_hash_params
end

def test_async_query_with_invalid_params
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'
assert_raises(DuckDB::Error) { @con.async_query('foo', 'bar') }

assert_raises(ArgumentError) { @con.async_query }
Expand Down Expand Up @@ -108,6 +112,7 @@ def test_async_query_stream_with_valid_params
end

def test_async_query_stream_with_invalid_params
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'
assert_raises(DuckDB::Error) { @con.async_query_stream('foo', 'bar') }

assert_raises(ArgumentError) { @con.async_query_stream }
Expand Down Expand Up @@ -177,11 +182,15 @@ def test_query_progress
"QueryProgress: total_rows_to_process(#{total_rows_to_process}) to be >= rows_processed(#{rows_processed})"
)

# test interrupt
@con.interrupt
while pending_result.state == :not_ready
pending_result.execute_task
assert(pending_result.state != :ready, 'pending_result.state should not be :ready')
if ENV['ASAN_TEST'].nil?
# test interrupt
@con.interrupt
while pending_result.state == :not_ready
pending_result.execute_task
assert(pending_result.state != :ready, 'pending_result.state should not be :ready')
end
else
skip 'test with ASAN'
end
end

Expand Down
4 changes: 4 additions & 0 deletions test/duckdb_test/database_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ def test_s_open_argument

assert_raises(TypeError) { DuckDB::Database.open('foo', 'bar') }
assert_raises(TypeError) { DuckDB::Database.open(1) }
end

def test_s_open_invalid_argument
skip('test with ASAN') if ENV['ASAN_TEST'] == '1'
assert_raises(DuckDB::Error) do
not_exist_path = "#{create_path}/#{create_path}"
DuckDB::Database.open(not_exist_path)
Expand Down Expand Up @@ -81,6 +84,7 @@ def test_connect_with_block
end

def test_close
skip 'asan test with exception' if ENV['ASAN_TEST'] == '1'
db = DuckDB::Database.open
con = db.connect
db.close
Expand Down
1 change: 1 addition & 0 deletions test/duckdb_test/extracted_statements_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def test_s_new
end

def test_s_new_with_invalid_sql
skip('test with ASAN') if ENV['ASAN_TEST'] == '1'
ex = assert_raises DuckDB::Error do
DuckDB::ExtractedStatements.new(@con, 'SELECT 1; INVALID STATEMENT; SELECT 3')
end
Expand Down
10 changes: 10 additions & 0 deletions test/duckdb_test/prepared_statement_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ def test_s_new
assert_raises(ArgumentError) { DuckDB::PreparedStatement.new }
assert_raises(TypeError) { DuckDB::PreparedStatement.new(@con, 1) }
assert_raises(TypeError) { DuckDB::PreparedStatement.new(1, 1) }
end

def test_s_new_with_duckdb_error
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'
assert_raises(DuckDB::Error) { DuckDB::PreparedStatement.new(@con, 'SELECT * FROM') }
end

Expand All @@ -121,7 +125,10 @@ def test_execute
stmt = DuckDB::PreparedStatement.new(@con, 'SELECT * FROM a')
result = stmt.execute
assert_instance_of(DuckDB::Result, result)
end

def test_execute_with_exception
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'
stmt = DuckDB::PreparedStatement.new(@con, 'SELECT * FROM a where id = ?')
assert_raises(DuckDB::Error) { stmt.execute }
end
Expand Down Expand Up @@ -150,6 +157,7 @@ def test_param_type
end

def test_clear_bindings
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'
stmt = DuckDB::PreparedStatement.new(@con, 'SELECT * FROM a WHERE id = $1')
stmt.bind(1, 1)
stmt.clear_bindings
Expand Down Expand Up @@ -428,6 +436,7 @@ def test_bind_varchar_date
end

def test_bind_varchar_date_with_invalid_timestamp_string
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'
stmt = DuckDB::PreparedStatement.new(@con, 'SELECT * FROM a WHERE col_date = $1')

stmt.bind_varchar(1, 'invalid_date_string')
Expand All @@ -443,6 +452,7 @@ def test_bind_varchar_timestamp
end

def test_bind_varchar_timestamp_with_invalid_timestamp_string
skip 'test with ASAN' if ENV['ASAN_TEST'] == '1'
stmt = DuckDB::PreparedStatement.new(@con, 'SELECT * FROM a WHERE col_timestamp = $1')

stmt.bind_varchar(1, 'invalid_timestamp_string')
Expand Down
Loading