diff --git a/test/test_orm_migration.rb b/test/test_orm_migration.rb new file mode 100644 index 0000000..08fff3e --- /dev/null +++ b/test/test_orm_migration.rb @@ -0,0 +1,156 @@ +require 'minitest/autorun' +require 'prism' +require 'tmpdir' + +class OrmMigrationTest < Minitest::Test + def setup + @store_dir = Dir.mktmpdir('prism-migration-store') + @migrations_dir = Dir.mktmpdir('prism-migration-files') + @store = Prism::Orm::Store.new(File.join(@store_dir, 'test.pstore')) + end + + def teardown + FileUtils.remove_entry(@store_dir) + FileUtils.remove_entry(@migrations_dir) + end + + def write_migration(version, class_name, body) + path = File.join(@migrations_dir, "#{version}_#{Prism::Inflector.underscore(class_name)}.rb") + File.write(path, <<~RUBY) + class #{class_name} < Prism::Orm::Migration + #{body} + end + RUBY + path + end + + def test_migrate_creates_table + write_migration('20260101000001', 'CreateWidgetsForMigrationTest', <<~RUBY) + def up + create_table :widgets_for_migration_test do |t| + t.string :name + end + end + + def down + drop_table :widgets_for_migration_test + end + RUBY + + migrator = Prism::Orm::Migrator.new(@store, @migrations_dir) + applied = migrator.migrate! + + assert_equal ['20260101000001'], applied + assert @store.table_exists?(:widgets_for_migration_test) + assert_equal ['20260101000001'], @store.applied_migrations + end + + def test_pending_excludes_applied_migrations + write_migration('20260101000002', 'CreateGizmosForMigrationTest', <<~RUBY) + def up + create_table(:gizmos_for_migration_test) { |t| t.string :name } + end + + def down + drop_table :gizmos_for_migration_test + end + RUBY + + migrator = Prism::Orm::Migrator.new(@store, @migrations_dir) + assert_equal 1, migrator.pending.size + migrator.migrate! + assert_empty migrator.pending + end + + def test_rollback_runs_down_and_forgets_version + write_migration('20260101000003', 'CreateSprocketsForMigrationTest', <<~RUBY) + def up + create_table(:sprockets_for_migration_test) { |t| t.string :name } + end + + def down + drop_table :sprockets_for_migration_test + end + RUBY + + migrator = Prism::Orm::Migrator.new(@store, @migrations_dir) + migrator.migrate! + assert @store.table_exists?(:sprockets_for_migration_test) + + rolled_back = migrator.rollback! + assert_equal ['20260101000003'], rolled_back + refute @store.table_exists?(:sprockets_for_migration_test) + assert_empty @store.applied_migrations + end + + def test_rollback_multiple_steps_reverts_in_reverse_order + write_migration('20260101000020', 'FirstMultiRollbackTest', <<~RUBY) + def up + create_table(:multi_rollback_a) { |t| t.string :name } + end + + def down + drop_table :multi_rollback_a + end + RUBY + write_migration('20260101000021', 'SecondMultiRollbackTest', <<~RUBY) + def up + create_table(:multi_rollback_b) { |t| t.string :name } + end + + def down + drop_table :multi_rollback_b + end + RUBY + + migrator = Prism::Orm::Migrator.new(@store, @migrations_dir) + migrator.migrate! + assert @store.table_exists?(:multi_rollback_a) + assert @store.table_exists?(:multi_rollback_b) + + reverted = migrator.rollback!(2) + assert_equal ['20260101000021', '20260101000020'], reverted + refute @store.table_exists?(:multi_rollback_a) + refute @store.table_exists?(:multi_rollback_b) + assert_empty @store.applied_migrations + end + + def test_add_and_remove_column_in_migration + write_migration('20260101000004', 'CreateThingiesForMigrationTest', <<~RUBY) + def up + create_table(:thingies_for_migration_test) { |t| t.string :name } + add_column :thingies_for_migration_test, :active + end + + def down + remove_column :thingies_for_migration_test, :active + drop_table :thingies_for_migration_test + end + RUBY + + Prism::Orm::Migrator.new(@store, @migrations_dir).migrate! + assert_includes @store.columns(:thingies_for_migration_test), 'active' + end + + def test_migrations_run_in_version_order + write_migration('20260101000010', 'SecondForOrderingTest', <<~RUBY) + def up + store.insert(:ordering_test_log, step: 'second') + end + + def down; end + RUBY + write_migration('20260101000005', 'FirstForOrderingTest', <<~RUBY) + def up + create_table(:ordering_test_log) { |t| t.string :step } + store.insert(:ordering_test_log, step: 'first') + end + + def down; end + RUBY + + Prism::Orm::Migrator.new(@store, @migrations_dir).migrate! + steps = @store.all(:ordering_test_log).map { |row| row['step'] } + assert_equal %w[first second], steps + end +end diff --git a/test/test_orm_transaction.rb b/test/test_orm_transaction.rb new file mode 100644 index 0000000..af92e32 --- /dev/null +++ b/test/test_orm_transaction.rb @@ -0,0 +1,39 @@ +require 'minitest/autorun' +require 'prism' +require 'tmpdir' + +class OrmTransactionTest < Minitest::Test + def setup + @dir = Dir.mktmpdir('prism-tx-store') + @store = Prism::Orm::Store.new(File.join(@dir, 'test.pstore')) + @store.create_table(:ledger, %w[id amount]) + end + + def teardown + FileUtils.remove_entry(@dir) + end + + def test_successful_transaction_commits_every_write + @store.transaction do + @store.insert(:ledger, amount: 10) + @store.insert(:ledger, amount: 20) + end + assert_equal [10, 20], @store.all(:ledger).map { |row| row['amount'] } + end + + def test_failed_transaction_rolls_back_every_write + assert_raises(RuntimeError) do + @store.transaction do + @store.insert(:ledger, amount: 10) + @store.insert(:ledger, amount: 20) + raise 'transfer failed midway' + end + end + assert_empty @store.all(:ledger), 'no row from the aborted transaction should be visible' + end + + def test_transaction_return_value_is_yielded_through + result = @store.transaction { @store.insert(:ledger, amount: 5) } + assert_equal 1, result + end +end