175 lines
5.4 KiB
Ruby
175 lines
5.4 KiB
Ruby
require 'minitest/autorun'
|
|
require 'prism'
|
|
require 'stringio'
|
|
require 'tmpdir'
|
|
require 'fileutils'
|
|
|
|
class CliDbTest < Minitest::Test
|
|
def setup
|
|
@workdir = Dir.mktmpdir('prism-cli-db')
|
|
@cli = Prism::Cli.new(@workdir)
|
|
@database = 'db/test.pstore'
|
|
FileUtils.mkdir_p(File.join(@workdir, 'db', 'migrate'))
|
|
end
|
|
|
|
def teardown
|
|
FileUtils.remove_entry(@workdir)
|
|
end
|
|
|
|
def write_migration(version, class_name, body)
|
|
path = File.join(@workdir, 'db', 'migrate', "#{version}_#{Prism::Inflector.underscore(class_name)}.rb")
|
|
File.write(path, <<~RUBY)
|
|
class #{class_name} < Prism::Orm::Migration
|
|
#{body}
|
|
end
|
|
RUBY
|
|
path
|
|
end
|
|
|
|
def widgets_migration(version = '20260101000001')
|
|
write_migration(version, 'CreateWidgetsForCliDbTest', <<~RUBY)
|
|
def up
|
|
create_table :widgets_for_cli_db_test do |t|
|
|
t.string :name
|
|
end
|
|
end
|
|
|
|
def down
|
|
drop_table :widgets_for_cli_db_test
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
def gadgets_migration(version = '20260101000002')
|
|
write_migration(version, 'CreateGadgetsForCliDbTest', <<~RUBY)
|
|
def up
|
|
create_table :gadgets_for_cli_db_test do |t|
|
|
t.string :label
|
|
end
|
|
end
|
|
|
|
def down
|
|
drop_table :gadgets_for_cli_db_test
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
def store
|
|
Prism::Orm::Store.new(File.join(@workdir, @database))
|
|
end
|
|
|
|
def test_db_migrate_applies_pending_migrations_and_reports_them
|
|
widgets_migration
|
|
out = StringIO.new
|
|
applied = @cli.db_migrate(["--database=#{@database}"], out: out)
|
|
|
|
assert_equal ['20260101000001'], applied
|
|
assert_includes out.string, 'migrated 20260101000001'
|
|
assert store.table_exists?(:widgets_for_cli_db_test)
|
|
end
|
|
|
|
def test_db_migrate_with_nothing_pending_reports_that_instead_of_erroring
|
|
widgets_migration
|
|
@cli.db_migrate(["--database=#{@database}"], out: StringIO.new)
|
|
|
|
out = StringIO.new
|
|
applied = @cli.db_migrate(["--database=#{@database}"], out: out)
|
|
|
|
assert_empty applied
|
|
assert_includes out.string, 'no pending migrations'
|
|
end
|
|
|
|
def test_db_migrate_dispatches_through_run
|
|
widgets_migration
|
|
capture_io { @cli.run(['db:migrate', "--database=#{@database}"]) }
|
|
assert store.table_exists?(:widgets_for_cli_db_test)
|
|
end
|
|
|
|
def test_db_rollback_defaults_to_one_step
|
|
widgets_migration
|
|
gadgets_migration
|
|
@cli.db_migrate(["--database=#{@database}"], out: StringIO.new)
|
|
assert store.table_exists?(:gadgets_for_cli_db_test)
|
|
|
|
out = StringIO.new
|
|
reverted = @cli.db_rollback(["--database=#{@database}"], out: out)
|
|
|
|
assert_equal ['20260101000002'], reverted
|
|
assert_includes out.string, 'rolled back 20260101000002'
|
|
refute store.table_exists?(:gadgets_for_cli_db_test)
|
|
assert store.table_exists?(:widgets_for_cli_db_test), 'earlier migration must survive a single-step rollback'
|
|
end
|
|
|
|
def test_db_rollback_honors_explicit_step_count
|
|
widgets_migration
|
|
gadgets_migration
|
|
@cli.db_migrate(["--database=#{@database}"], out: StringIO.new)
|
|
|
|
reverted = @cli.db_rollback(["--database=#{@database}", '--step=2'], out: StringIO.new)
|
|
|
|
assert_equal ['20260101000002', '20260101000001'], reverted
|
|
refute store.table_exists?(:gadgets_for_cli_db_test)
|
|
refute store.table_exists?(:widgets_for_cli_db_test)
|
|
end
|
|
|
|
def test_db_rollback_with_nothing_applied_reports_that_instead_of_erroring
|
|
widgets_migration
|
|
out = StringIO.new
|
|
reverted = @cli.db_rollback(["--database=#{@database}"], out: out)
|
|
|
|
assert_empty reverted
|
|
assert_includes out.string, 'nothing to roll back'
|
|
end
|
|
|
|
def test_db_status_marks_applied_migrations_up_and_the_rest_down
|
|
widgets_migration
|
|
gadgets_migration
|
|
@cli.db_migrate(["--database=#{@database}"], out: StringIO.new)
|
|
@cli.db_rollback(["--database=#{@database}"], out: StringIO.new)
|
|
|
|
out = StringIO.new
|
|
status = @cli.db_status(["--database=#{@database}"], out: out)
|
|
|
|
assert_equal [['20260101000001', true], ['20260101000002', false]],
|
|
status.map { |entry, applied| [entry.version, applied] }
|
|
assert_match(/up\s+20260101000001\s+create_widgets_for_cli_db_test/, out.string)
|
|
assert_match(/down\s+20260101000002\s+create_gadgets_for_cli_db_test/, out.string)
|
|
end
|
|
|
|
def test_db_status_with_no_migration_files_prints_only_the_header
|
|
out = StringIO.new
|
|
status = @cli.db_status(["--database=#{@database}"], out: out)
|
|
|
|
assert_empty status
|
|
assert_equal "STATUS VERSION NAME\n", out.string
|
|
end
|
|
|
|
def test_db_commands_use_the_migrations_flag_to_find_a_custom_directory
|
|
FileUtils.mkdir_p(File.join(@workdir, 'other_migrations'))
|
|
File.write(File.join(@workdir, 'other_migrations', '20260101000003_create_thingies_for_cli_db_test.rb'), <<~RUBY)
|
|
class CreateThingiesForCliDbTest < Prism::Orm::Migration
|
|
def up
|
|
create_table :thingies_for_cli_db_test do |t|
|
|
t.string :name
|
|
end
|
|
end
|
|
|
|
def down
|
|
drop_table :thingies_for_cli_db_test
|
|
end
|
|
end
|
|
RUBY
|
|
|
|
applied = @cli.db_migrate(["--database=#{@database}", '--migrations=other_migrations'], out: StringIO.new)
|
|
|
|
assert_equal ['20260101000003'], applied
|
|
assert store.table_exists?(:thingies_for_cli_db_test)
|
|
end
|
|
|
|
def test_db_options_reject_unknown_flags
|
|
assert_raises(Prism::Cli::UsageError) { @cli.db_migrate(['--bogus=1']) }
|
|
assert_raises(Prism::Cli::UsageError) { @cli.db_rollback(['--bogus=1']) }
|
|
assert_raises(Prism::Cli::UsageError) { @cli.db_status(['--bogus=1']) }
|
|
end
|
|
end
|