diff options
Diffstat (limited to 'gems/click_house-client/spec/click_house')
6 files changed, 269 insertions, 2 deletions
diff --git a/gems/click_house-client/spec/click_house/client/bind_index_manager_spec.rb b/gems/click_house-client/spec/click_house/client/bind_index_manager_spec.rb new file mode 100644 index 00000000000..38e0865676a --- /dev/null +++ b/gems/click_house-client/spec/click_house/client/bind_index_manager_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ClickHouse::Client::BindIndexManager do + describe '#next_bind_str' do + context 'when initialized without a start index' do + let(:bind_manager) { described_class.new } + + it 'starts from index 1 by default' do + expect(bind_manager.next_bind_str).to eq('$1') + end + + it 'increments the bind string on subsequent calls' do + bind_manager.next_bind_str + expect(bind_manager.next_bind_str).to eq('$2') + end + end + + context 'when initialized with a start index' do + let(:bind_manager) { described_class.new(2) } + + it 'starts from the given index' do + expect(bind_manager.next_bind_str).to eq('$2') + end + + it 'increments the bind string on subsequent calls' do + bind_manager.next_bind_str + expect(bind_manager.next_bind_str).to eq('$3') + end + end + end +end diff --git a/gems/click_house-client/spec/click_house/client/database_spec.rb b/gems/click_house-client/spec/click_house/client/database_spec.rb index a74d4a119a4..fdb4c72c0cb 100644 --- a/gems/click_house-client/spec/click_house/client/database_spec.rb +++ b/gems/click_house-client/spec/click_house/client/database_spec.rb @@ -24,7 +24,6 @@ RSpec.describe ClickHouse::Client::Database do describe '#headers' do it 'returns the correct headers' do expect(database.headers).to eq({ - "Content-Encoding" => "gzip", "X-ClickHouse-Format" => "JSON", 'X-ClickHouse-User' => 'user', 'X-ClickHouse-Key' => 'pass' diff --git a/gems/click_house-client/spec/click_house/client/formatter_spec.rb b/gems/click_house-client/spec/click_house/client/formatter_spec.rb new file mode 100644 index 00000000000..0af3aa0bdbc --- /dev/null +++ b/gems/click_house-client/spec/click_house/client/formatter_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ClickHouse::Client::Formatter do + it 'formats values according to types in metadata' do + # this query here is just for documentation purposes, it generates the response below + _query = <<~SQL.squish + SELECT toUInt64(1) as uint64, + toDateTime64('2016-06-15 23:00:00', 6, 'UTC') as datetime64_6, + INTERVAL 1 second as interval_second + SQL + + response_json = <<~JSON +{ + "meta": + [ + { + "name": "uint64", + "type": "UInt64" + }, + { + "name": "datetime64_6", + "type": "DateTime64(6, 'UTC')" + }, + { + "name": "interval_second", + "type": "IntervalSecond" + } + ], + + "data": + [ + { + "uint64": "1", + "datetime64_6": "2016-06-15 23:00:00.000000", + "interval_second": "1" + } + ], + + "rows": 1, + + "statistics": + { + "elapsed": 0.002101, + "rows_read": 1, + "bytes_read": 1 + } +} + JSON + + parsed_response = JSON.parse(response_json) + formatted_response = described_class.format(parsed_response) + + expect(formatted_response).to( + eq( + [{ "uint64" => 1, + "datetime64_6" => ActiveSupport::TimeZone["UTC"].parse("2016-06-15 23:00:00"), + "interval_second" => 1.second }] + ) + ) + end +end diff --git a/gems/click_house-client/spec/click_house/client/query_like_spec.rb b/gems/click_house-client/spec/click_house/client/query_like_spec.rb new file mode 100644 index 00000000000..8b8426bd5fd --- /dev/null +++ b/gems/click_house-client/spec/click_house/client/query_like_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ClickHouse::Client::QueryLike do + subject(:query) { described_class.new } + + describe '#to_sql' do + it { expect { query.to_sql }.to raise_error(NotImplementedError) } + end + + describe '#to_redacted_sql' do + it { expect { query.to_redacted_sql }.to raise_error(NotImplementedError) } + end +end diff --git a/gems/click_house-client/spec/click_house/client/query_spec.rb b/gems/click_house-client/spec/click_house/client/query_spec.rb new file mode 100644 index 00000000000..82733e523b1 --- /dev/null +++ b/gems/click_house-client/spec/click_house/client/query_spec.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ClickHouse::Client::Query do + subject(:query) { described_class.new(raw_query: raw_query, placeholders: placeholders) } + + let(:sql) { query.to_sql } + let(:redacted_sql) { query.to_redacted_sql } + + context 'when using no placeholders' do + let(:raw_query) { 'SELECT * FROM events' } + let(:placeholders) { nil } + + it { expect(sql).to eq(raw_query) } + it { expect(redacted_sql).to eq(raw_query) } + + context 'when placeholders is an empty hash' do + let(:placeholders) { {} } + + it { expect(sql).to eq(raw_query) } + it { expect(redacted_sql).to eq(raw_query) } + end + end + + context 'when placeholders are given' do + let(:raw_query) { 'SELECT * FROM events WHERE id = {id:UInt64}' } + let(:placeholders) { { id: 1 } } + + it { expect(sql).to eq(raw_query) } + it { expect(redacted_sql).to eq('SELECT * FROM events WHERE id = $1') } + end + + context 'when multiple placeholders are given' do + let(:raw_query) do + <<~SQL.squish + SELECT * + FROM events + WHERE + id = {id:UInt64} AND + title = {some_title:String} AND + another_id = {id:UInt64} + SQL + end + + let(:placeholders) { { id: 1, some_title: "'title'" } } + + it do + expect(sql).to eq(raw_query) + end + + it do + expect(redacted_sql).to eq( + <<~SQL.squish + SELECT * + FROM events + WHERE + id = $1 AND + title = $2 AND + another_id = $3 + SQL + ) + end + end + + context 'when dealing with subqueries' do + let(:raw_query) { 'SELECT * FROM events WHERE id < {min_id:UInt64} AND id IN ({q:Subquery})' } + + let(:subquery) do + described_class.new(raw_query: 'SELECT id FROM events WHERE id > {max_id:UInt64}', placeholders: { max_id: 11 }) + end + + let(:placeholders) { { min_id: 100, q: subquery } } + + it 'replaces the subquery but preserves the other placeholders' do + q = 'SELECT * FROM events WHERE id < {min_id:UInt64} AND id IN (SELECT id FROM events WHERE id > {max_id:UInt64})' + expect(sql).to eq(q) + end + + it 'replaces the subquery and replaces the placeholders with indexed values' do + expect(redacted_sql).to eq('SELECT * FROM events WHERE id < $1 AND id IN (SELECT id FROM events WHERE id > $2)') + end + + it 'merges the placeholders' do + expect(query.placeholders).to eq({ min_id: 100, max_id: 11 }) + end + end + + describe 'validation' do + context 'when SQL string is empty' do + let(:raw_query) { '' } + let(:placeholders) { {} } + + it 'raises error' do + expect { query }.to raise_error(ClickHouse::Client::QueryError, /Empty query string given/) + end + end + + context 'when SQL string is nil' do + let(:raw_query) { nil } + let(:placeholders) { {} } + + it 'raises error' do + expect { query }.to raise_error(ClickHouse::Client::QueryError, /Empty query string given/) + end + end + + context 'when same placeholder value does not match' do + let(:raw_query) { 'SELECT id FROM events WHERE id = {id:UInt64} AND id IN ({q:Subquery})' } + + let(:subquery) do + subquery_string = 'SELECT id FROM events WHERE id = {id:UInt64}' + described_class.new(raw_query: subquery_string, placeholders: { id: 10 }) + end + + let(:placeholders) { { id: 5, q: subquery } } + + it 'raises error' do + expect do + query.placeholders + end.to raise_error(ClickHouse::Client::QueryError, /mismatching values for the 'id' placeholder/) + end + end + end +end diff --git a/gems/click_house-client/spec/click_house/client_spec.rb b/gems/click_house-client/spec/click_house/client_spec.rb index 883199198ba..ab2407a83d7 100644 --- a/gems/click_house-client/spec/click_house/client_spec.rb +++ b/gems/click_house-client/spec/click_house/client_spec.rb @@ -30,6 +30,9 @@ RSpec.describe ClickHouse::Client do let(:configuration) do ClickHouse::Client::Configuration.new.tap do |config| + config.log_proc = ->(query) do + { query_string: query.to_sql } + end config.register_database(:test_db, **database_config) config.http_post_proc = ->(_url, _headers, _query) { body = File.read(query_result_fixture) @@ -71,7 +74,7 @@ RSpec.describe ClickHouse::Client do end context 'when the DB is not configured' do - it 'raises erro' do + it 'raises error' do expect do described_class.select('SELECT * FROM issues', :different_db, configuration) end.to raise_error(ClickHouse::Client::ConfigurationError, /not configured/) @@ -94,5 +97,34 @@ RSpec.describe ClickHouse::Client do end.to raise_error(ClickHouse::Client::DatabaseError, 'some error') end end + + describe 'default logging' do + let(:fake_logger) { instance_double("Logger", info: 'logged!') } + let(:query_string) { 'SELECT * FROM issues' } + + before do + configuration.logger = fake_logger + end + + shared_examples 'proper logging' do + it 'calls the custom logger and log_proc' do + expect(fake_logger).to receive(:info).at_least(:once).with({ query_string: query_string }) + + described_class.select(query_object, :test_db, configuration) + end + end + + context 'when query is a string' do # rubocop:disable RSpec/MultipleMemoizedHelpers + let(:query_object) { query_string } + + it_behaves_like 'proper logging' + end + + context 'when query is a Query object' do # rubocop:disable RSpec/MultipleMemoizedHelpers + let(:query_object) { ClickHouse::Client::Query.new(raw_query: query_string) } + + it_behaves_like 'proper logging' + end + end end end |