Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: enable acceptance tests on emulator #70

Merged
merged 13 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/acceptance-tests-on-emulator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
on:
push:
branches:
- master
pull_request:
name: acceptance tests on emulator
jobs:
test:
runs-on: ubuntu-latest

services:
emulator:
image: gcr.io/cloud-spanner-emulator/emulator:latest
ports:
- 9010:9010
- 9020:9020

strategy:
max-parallel: 4
matrix:
ruby: [2.5, 2.6, 2.7, 3.0]
steps:
- uses: actions/checkout@v2
- name: Set up Ruby
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby
# (see https://github.com/ruby/setup-ruby#versioning):
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
ruby-version: ${{ matrix.ruby }}
- name: Install dependencies
run: bundle install
- name: Run acceptance tests on emulator
run: bundle exec rake acceptance
env:
SPANNER_EMULATOR_HOST: localhost:9010
SPANNER_TEST_PROJECT: test-project
SPANNER_TEST_INSTANCE: test-instance
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ build-iPhoneSimulator/
#
# vendor/Pods/

# Ignore RubyMine project files
.idea

## Documentation cache and generated files:
/.yardoc/
/_yardoc/
Expand Down
7 changes: 5 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,17 @@ desc "Run the spanner connector acceptance tests."
task :acceptance, :project, :keyfile, :instance do |t, args|
project = args[:project]
project ||= ENV["SPANNER_TEST_PROJECT"] || ENV["GCLOUD_TEST_PROJECT"]
emulator_host = args[:emulator_host]
emulator_host ||= ENV["SPANNER_EMULATOR_HOST"]
keyfile = args[:keyfile]
keyfile ||= ENV["SPANNER_TEST_KEYFILE"] || ENV["GCLOUD_TEST_KEYFILE"]
if keyfile
keyfile = File.read keyfile
else
keyfile ||= ENV["SPANNER_TEST_KEYFILE_JSON"] || ENV["GCLOUD_TEST_KEYFILE_JSON"]
end
if project.nil? || keyfile.nil?
fail "You must provide a project and keyfile."
if project.nil? || (keyfile.nil? && emulator_host.nil?)
fail "You must provide a project and keyfile or emulator host name."
end
instance = args[:instance]
instance ||= ENV["SPANNER_TEST_INSTANCE"]
xiangshen-dk marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -51,6 +53,7 @@ task :acceptance, :project, :keyfile, :instance do |t, args|
ENV["SPANNER_PROJECT"] = project
ENV["SPANNER_KEYFILE_JSON"] = keyfile
ENV["SPANNER_TEST_INSTANCE"] = instance
ENV["SPANNER_EMULATOR_HOST"] = emulator_host

Rake::TestTask.new :run do |t|
t.libs << "acceptance"
Expand Down
10 changes: 4 additions & 6 deletions acceptance/cases/migration/change_schema_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def test_create_table_with_not_null_column
t.column :foo, :string, null: false
end

assert_raises ActiveRecord::NotNullViolation do
assert_raises ActiveRecord::StatementInvalid do
connection.transaction {
connection.execute "insert into testings (id, foo) values (#{generate_id}, NULL)"
}
Expand Down Expand Up @@ -246,8 +246,6 @@ def test_change_column_quotes_column_names
end

def test_keeping_notnull_constraints_on_change
skip "Unimplemented error: Cannot add NOT NULL column to existing table."

connection.create_table :testings do |t|
t.column :title, :string
end
Expand All @@ -260,15 +258,15 @@ def test_keeping_notnull_constraints_on_change

assert_nothing_raised {
person_klass.connection.transaction {
person_klass.connection.execute("insert into testings (id, title) values (#{generate_id}, tester')")
person_klass.connection.execute("insert into testings (id, title, wealth) values (#{generate_id}, 'tester', 100000)")
}
}

# change column, make it nullable
person_klass.connection.change_column "testings", "wealth", :integer, null: true
person_klass.reset_column_information
assert_nil person_klass.columns_hash["money"].default
assert_equal true, person_klass.columns_hash["money"].null
assert_nil person_klass.columns_hash["wealth"].default
assert_equal true, person_klass.columns_hash["wealth"].null
end

def test_change_column_null
Expand Down
10 changes: 10 additions & 0 deletions acceptance/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
def connector_config
{
"adapter" => "spanner",
"emulator_host" => ENV["SPANNER_EMULATOR_HOST"],
"project" => ENV["SPANNER_TEST_PROJECT"],
"instance" => ENV["SPANNER_TEST_INSTANCE"],
"credentials" => ENV["SPANNER_TEST_KEYFILE"],
Expand All @@ -40,6 +41,15 @@ def spanner
end

def spanner_instance
if ENV["SPANNER_EMULATOR_HOST"]
unless spanner.instance ENV["SPANNER_TEST_INSTANCE"]
job = spanner.create_instance ENV["SPANNER_TEST_INSTANCE"],
name: "Automatically Created Test Instance",
config: "emulator-config",
nodes: 1
job.wait_until_done!
end
end
$spanner_instance ||= spanner.instance ENV["SPANNER_TEST_INSTANCE"]
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def execute_pending_ddl

def begin_db_transaction
log "BEGIN" do
@connection.begin_trasaction
@connection.begin_transaction
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/active_record/connection_adapters/spanner/quoting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ module ConnectionAdapters
module Spanner
module Quoting
def quote_column_name name
self.class.quoted_column_names[name] ||= "`#{super.gsub '`', '``'}`"
self.class.quoted_column_names[name] ||= "`#{super.gsub '`', '``'}`".freeze
end

def quote_table_name name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,18 @@ def visit_DropTableDefinition o
end

def visit_ColumnDefinition o
o.sql_type = type_to_sql o.type, o.options
o.sql_type = type_to_sql o.type, **o.options
column_sql = +"#{quote_column_name o.name} #{o.sql_type}"
add_column_options! column_sql, column_options(o)
column_sql
end

def visit_AddColumnDefinition o
# Overridden to add the optional COLUMN keyword. The keyword is only optional
# on real Cloud Spanner, the emulator requires the COLUMN keyword to be included.
+"ADD COLUMN #{accept o.column}"
end

def visit_DropColumnDefinition o
"ALTER TABLE #{quote_table_name o.table_name} DROP" \
" COLUMN #{quote_column_name o.name}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def on_delete

def references *args, **options
args.each do |ref_name|
Spanner::ReferenceDefinition.new(ref_name, options).add_to(self)
Spanner::ReferenceDefinition.new(ref_name, **options).add_to(self)
end
end
alias belongs_to references
Expand Down
37 changes: 21 additions & 16 deletions lib/active_record/connection_adapters/spanner/schema_statements.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def create_table table_name, **options
if pk.is_a? Array
td.primary_keys pk
else
td.primary_key pk, options.fetch(:id, :primary_key), {}
td.primary_key pk, options.fetch(:id, :primary_key), **{}
xiangshen-dk marked this conversation as resolved.
Show resolved Hide resolved
end
end

Expand All @@ -62,7 +62,7 @@ def create_table table_name, **options
statements << schema_creation.accept(td)

td.indexes.each do |column_name, index_options|
id = create_index_definition table_name, column_name, index_options
id = create_index_definition table_name, column_name, **index_options
statements << schema_creation.accept(id)
end

Expand All @@ -74,12 +74,17 @@ def drop_table table_name, options = {}
execute_schema_statements statements
end

# Creates a join table that uses all the columns in the table as the primary key.
xiangshen-dk marked this conversation as resolved.
Show resolved Hide resolved
def create_join_table table_1, table_2, column_options: {}, **options
return super unless block_given?

super do |td|
yield td
td.primary_key :id unless td.columns.any?(&:primary_key?)
unless td.columns.any?(&:primary_key?)
td.columns.each do |col|
def col.primary_key?
true
end
end
end
yield td if block_given?
end
end

Expand Down Expand Up @@ -113,7 +118,7 @@ def add_column table_name, column_name, type, **options
nullable = options.delete(:null) == false

at = create_alter_table table_name
at.add_column column_name, type, options
at.add_column column_name, type, **options

statements = [schema_creation.accept(at)]

Expand Down Expand Up @@ -184,7 +189,7 @@ def change_column table_name, column_name, type, options = {} # rubocop:disable
end

td = create_table_definition table_name
cd = td.new_column_definition column.name, type, options
cd = td.new_column_definition column.name, type, **options

ccd = Spanner::ChangeColumnDefinition.new table_name, cd, column.name
statements << schema_creation.accept(ccd)
Expand All @@ -194,7 +199,7 @@ def change_column table_name, column_name, type, options = {} # rubocop:disable
id = create_index_definition(
table_name,
index.column_names,
index.options
**index.options
)
statements << schema_creation.accept(id)
end
Expand Down Expand Up @@ -223,7 +228,7 @@ def rename_column table_name, column_name, new_column_name

# Add Column
cast_type = lookup_cast_type column.spanner_type
add_column table_name, new_column_name, cast_type.type, column.options
add_column table_name, new_column_name, cast_type.type, **column.options

# Copy data
copy_data table_name, column_name, new_column_name
Expand Down Expand Up @@ -264,7 +269,7 @@ def index_name_exists? table_name, index_name
end

def add_index table_name, column_name, options = {}
id = create_index_definition table_name, column_name, options
id = create_index_definition table_name, column_name, **options

if data_source_exists?(table_name) &&
index_name_exists?(table_name, id.name)
Expand Down Expand Up @@ -363,7 +368,7 @@ def remove_foreign_key from_table, to_table = nil, **options
# Reference Column

def add_reference table_name, ref_name, **options
ReferenceDefinition.new(ref_name, options).add_to(
ReferenceDefinition.new(ref_name, **options).add_to(
update_table_definition(table_name, self)
)
end
Expand Down Expand Up @@ -404,7 +409,7 @@ def schema_creation
end

def create_table_definition *args
TableDefinition.new self, *args
TableDefinition.new self, args[0], options: args[1]
end

def able_to_ddl_batch? table_name
Expand Down Expand Up @@ -519,13 +524,13 @@ def execute_schema_statements statements, with_batching: true
end

def information_schema
info_scheam = \
info_schema = \
ActiveRecordSpannerAdapter::Connection.information_schema @config

return info_scheam unless block_given?
return info_schema unless block_given?

execute_pending_ddl
yield info_scheam
yield info_schema
end
end
end
Expand Down
19 changes: 14 additions & 5 deletions lib/activerecord_spanner_adapter/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,20 @@ def self.information_schema config
end

def session
@last_used = Time.current
@session ||= spanner.create_session instance_id, database_id
end
alias connect! session

def active?
# This method should not initialize a session.
unless @session
return false
end
# Assume that it is still active if it has been used in the past 50 minutes.
if ((Time.current - @last_used) / 60).round < 50
return true
end
session.execute_query "SELECT 1"
true
rescue StandardError
Expand Down Expand Up @@ -113,7 +122,7 @@ def execute_query sql, params: nil, transaction_required: nil
end

if transaction_required && current_transaction.nil?
transaction = begin_trasaction
transaction = begin_transaction
end

session.execute_query \
Expand All @@ -133,7 +142,7 @@ def execute_query sql, params: nil, transaction_required: nil

# Transactions

def begin_trasaction
def begin_transaction
raise "Nested transactions are not allowed" if current_transaction
self.current_transaction = session.create_transaction
end
Expand Down Expand Up @@ -178,10 +187,10 @@ def transaction_selector
id: current_transaction.transaction_id
end

def snapshot sql, options = {}
def snapshot sql, _options = {}
raise "Nested snapshots are not allowed" if current_transaction

session.snapshot options do |snp|
session.snapshot do |snp|
xiangshen-dk marked this conversation as resolved.
Show resolved Hide resolved
snp.execute_query sql
end
rescue Google::Cloud::UnavailableError
Expand All @@ -193,7 +202,7 @@ def truncate table_name
end

def self.database_path config
"#{config[:project]}/#{config[:instance]}/#{config[:database]}"
"#{config[:emulator_host]}/#{config[:project]}/#{config[:instance]}/#{config[:database]}"
xiangshen-dk marked this conversation as resolved.
Show resolved Hide resolved
end

private
Expand Down