Packages
ecto_sql
3.5.3
3.14.0
3.13.5
3.13.4
3.13.3
3.13.2
3.13.1
3.13.0
3.12.1
3.12.0
3.11.3
3.11.2
3.11.1
3.11.0
3.10.2
3.10.1
3.10.0
3.9.2
3.9.1
3.9.0
3.8.3
3.8.2
3.8.1
3.8.0
3.7.2
3.7.1
3.7.0
3.6.2
3.6.1
3.6.0
3.5.4
3.5.3
3.5.2
3.5.1
3.5.0
3.5.0-rc.1
3.5.0-rc.0
3.4.5
3.4.4
3.4.3
3.4.2
3.4.1
3.4.0
3.3.4
3.3.3
3.3.2
3.3.1
3.3.0
3.2.2
3.2.1
3.2.0
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
3.0.0-rc.1
3.0.0-rc.0
SQL-based adapters for Ecto and database migrations
Current section
Files
Jump to
Current section
Files
integration_test/sql/migrator.exs
Code.require_file "../support/file_helpers.exs", __DIR__
defmodule Ecto.Integration.MigratorTest do
use Ecto.Integration.Case
import Support.FileHelpers
import ExUnit.CaptureLog
import Ecto.Migrator
alias Ecto.Integration.{TestRepo, PoolRepo}
alias Ecto.Migration.SchemaMigration
setup config do
Process.register(self(), config.test)
PoolRepo.delete_all(SchemaMigration)
:ok
end
defmodule AnotherSchemaMigration do
use Ecto.Migration
def change do
execute TestRepo.create_prefix("bad_schema_migrations"),
TestRepo.drop_prefix("bad_schema_migrations")
create table(:schema_migrations, prefix: "bad_schema_migrations") do
add :version, :string
add :inserted_at, :integer
end
end
end
defmodule BrokenLinkMigration do
use Ecto.Migration
def change do
Task.start_link(fn -> raise "oops" end)
Process.sleep(:infinity)
end
end
defmodule GoodMigration do
use Ecto.Migration
def up do
create table(:good_migration)
end
def down do
drop table(:good_migration)
end
end
defmodule BadMigration do
use Ecto.Migration
def change do
execute "CREATE WHAT"
end
end
test "migrations up and down" do
assert migrated_versions(PoolRepo) == []
assert up(PoolRepo, 31, GoodMigration, log: false) == :ok
[migration] = PoolRepo.all(SchemaMigration)
assert migration.version == 31
assert migration.inserted_at
assert migrated_versions(PoolRepo) == [31]
assert up(PoolRepo, 31, GoodMigration, log: false) == :already_up
assert migrated_versions(PoolRepo) == [31]
assert down(PoolRepo, 32, GoodMigration, log: false) == :already_down
assert migrated_versions(PoolRepo) == [31]
assert down(PoolRepo, 31, GoodMigration, log: false) == :ok
assert migrated_versions(PoolRepo) == []
end
test "does not commit migration if insert into schema migration fails" do
# First we create a new schema migration table in another prefix
assert up(PoolRepo, 33, AnotherSchemaMigration, log: false) == :ok
assert migrated_versions(PoolRepo) == [33]
assert capture_log(fn ->
catch_error(up(PoolRepo, 34, GoodMigration, log: false, prefix: "bad_schema_migrations"))
catch_error(PoolRepo.all("good_migration"))
catch_error(PoolRepo.all("good_migration", prefix: "bad_schema_migrations"))
end) =~ "Could not update schema migrations"
assert down(PoolRepo, 33, AnotherSchemaMigration, log: false) == :ok
end
test "bad execute migration" do
assert catch_error(up(PoolRepo, 31, BadMigration, log: false))
end
test "broken link migration" do
Process.flag(:trap_exit, true)
assert capture_log(fn ->
{:ok, pid} = Task.start_link(fn -> up(PoolRepo, 31, BrokenLinkMigration, log: false) end)
assert_receive {:EXIT, ^pid, _}
end) =~ "oops"
assert capture_log(fn ->
catch_exit(up(PoolRepo, 31, BrokenLinkMigration, log: false))
end) =~ "oops"
end
test "run up to/step migration", config do
in_tmp fn path ->
create_migration(47, config)
create_migration(48, config)
assert [47] = run(PoolRepo, path, :up, step: 1, log: false)
assert count_entries() == 1
assert [48] = run(PoolRepo, path, :up, to: 48, log: false)
end
end
test "run down to/step migration", config do
in_tmp fn path ->
migrations = [
create_migration(49, config),
create_migration(50, config),
]
assert [49, 50] = run(PoolRepo, path, :up, all: true, log: false)
purge migrations
assert [50] = run(PoolRepo, path, :down, step: 1, log: false)
purge migrations
assert count_entries() == 1
assert [50] = run(PoolRepo, path, :up, to: 50, log: false)
end
end
test "runs all migrations", config do
in_tmp fn path ->
migrations = [
create_migration(53, config),
create_migration(54, config),
]
assert [53, 54] = run(PoolRepo, path, :up, all: true, log: false)
assert [] = run(PoolRepo, path, :up, all: true, log: false)
purge migrations
assert [54, 53] = run(PoolRepo, path, :down, all: true, log: false)
purge migrations
assert count_entries() == 0
assert [53, 54] = run(PoolRepo, path, :up, all: true, log: false)
end
end
test "does not commit half transactions on bad syntax", config do
in_tmp fn path ->
migrations = [
create_migration(64, config),
create_migration("65_+", config)
]
assert_raise SyntaxError, fn ->
run(PoolRepo, path, :up, all: true, log: false)
end
refute_received {:up, _}
assert count_entries() == 0
purge migrations
end
end
test "raises when connection pool is too small" do
config = Application.fetch_env!(:ecto_sql, PoolRepo)
config = Keyword.merge(config, pool_size: 1)
Application.put_env(:ecto_sql, __MODULE__.SingleConnectionRepo, config)
defmodule SingleConnectionRepo do
use Ecto.Repo, otp_app: :ecto_sql, adapter: PoolRepo.__adapter__()
end
{:ok, _pid} = SingleConnectionRepo.start_link()
in_tmp fn path ->
exception_message = ~r/Migrations failed to run because the connection pool size is less than 2/
assert_raise Ecto.MigrationError, exception_message, fn ->
run(SingleConnectionRepo, path, :up, all: true, log: false)
end
end
end
test "does not raise when connection pool is too small but there is no lock" do
config = Application.fetch_env!(:ecto_sql, PoolRepo)
config = Keyword.merge(config, pool_size: 1, migration_lock: nil)
Application.put_env(:ecto_sql, __MODULE__.SingleConnectionNoLockRepo, config)
defmodule SingleConnectionNoLockRepo do
use Ecto.Repo, otp_app: :ecto_sql, adapter: PoolRepo.__adapter__()
end
{:ok, _pid} = SingleConnectionNoLockRepo.start_link()
in_tmp fn path ->
run(SingleConnectionNoLockRepo, path, :up, all: true, log: false)
end
end
defp count_entries() do
PoolRepo.aggregate(SchemaMigration, :count, :version)
end
defp create_migration(num, config) do
module = Module.concat(__MODULE__, "Migration#{num}")
File.write! "#{num}_migration_#{num}.exs", """
defmodule #{module} do
use Ecto.Migration
def up do
send #{inspect config.test}, {:up, #{inspect num}}
end
def down do
send #{inspect config.test}, {:down, #{inspect num}}
end
end
"""
module
end
defp purge(modules) do
Enum.each(List.wrap(modules), fn m ->
:code.delete m
:code.purge m
end)
end
end