Skip to content

Comments

ActiveRecord::Migration.maintain_test_schema! doesn't work with structure.sql#15394

Merged
senny merged 2 commits intorails:masterfrom
morgoth:fix-automatic-maintaining-test-schema-for-sql-format
Jun 12, 2014
Merged

ActiveRecord::Migration.maintain_test_schema! doesn't work with structure.sql#15394
senny merged 2 commits intorails:masterfrom
morgoth:fix-automatic-maintaining-test-schema-for-sql-format

Conversation

@morgoth
Copy link
Member

@morgoth morgoth commented Jun 1, 2014

Introduced in rails 4.1.
Checked using sqlite3 and postgres.

At the end of calling ActiveRecord::Migration.maintain_test_schema! this method is called:

def load_schema(format = ActiveRecord::Base.schema_format, file = nil)
which later, after choosing database adapter calls method, in example on sqlite3 adapter:

So at the very end it runs: sqlite3 db/test.sqlite3 < db/structure.sql

This however can result in error like:

Error: near line 1: table "schema_migrations" already exists
Error: near line 2: index unique_schema_migrations already exists
Error: near line 3: table "users" already exists
Error: near line 4: UNIQUE constraint failed: schema_migrations.version

This error can happen when we created migration to add column to existing table.

It looks like it's necessary to always purge database before loading sql file and adding:

purge(current_config)
create(current_config)

before line

structure_load(current_config, file)
fixes the issue.
I'm not sure if that is the best place however.

Similar issue was noted in #13528 (comment) by @kevintyll

Please, let me know if the issue is unclear, I can submit example app then.
If you think that's the correct way of fixing it, I can prepare a PR.

Addressing to @jonleighton as he is the author of this feature.

@rafaelfranca rafaelfranca added this to the 4.1.3 milestone May 28, 2014
@senny
Copy link
Member

senny commented May 29, 2014

I can confirm this issue. Have experienced it in my own applications.

@morgoth
Copy link
Member Author

morgoth commented Jun 1, 2014

@senny @rafaelfranca I added PR that fixes the issue. Please, let me know if some parts can be improved.

@szimek
Copy link
Contributor

szimek commented Jun 10, 2014

Got this issue as well.

@907th
Copy link
Contributor

907th commented Jun 11, 2014

Confirm

@senny senny self-assigned this Jun 11, 2014
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to create again? purge should already do that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not true for sqlite: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb#L17-L24

Maybe we should change purge on this adapter to create database as it is in pg and mysql?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should have the same semantics for sure. The description in the Rake task is: "Empty the test database"
To me this implies that the database still exists. Let's change the SQLite3 adapter.

@senny
Copy link
Member

senny commented Jun 11, 2014

@morgoth I am working on foreign key support for Rails 4.2. Once schema.rb will be able to create foreign key, we can no longer rely on force: true from the create_table statements. I think we can use the same solution for that problem as well. Let's also purge when loading from schema.rb.

@morgoth
Copy link
Member Author

morgoth commented Jun 11, 2014

@senny should I add purge when loading from schema.rb in this PR? Probably it will be backported to 4.1, so this change wont be needed there.

@senny
Copy link
Member

senny commented Jun 11, 2014

@morgoth At this point I do think we should backport the purge for schema.rb as well. I've seen a couple of situations where the test db got out of sync and couldn't be fixed by the automatic maintenance. The last resort was to rake db:test:prepare which is deprecated. I know this would be a change in behavior but it will make the process more transparent for the user.

/cc @rafaelfranca

@morgoth
Copy link
Member Author

morgoth commented Jun 11, 2014

@senny I updated PR with your suggeestions

@senny
Copy link
Member

senny commented Jun 11, 2014

@morgoth thanks man 💛 I'll need some time to make sure we don't run into regressions. Will ping you back by tomorrow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what promted the addition of this test? Is it actually failing when we remove the purge?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly.
To see it failing we must change structure and try to load it to existing database.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the absolute minimal test-case to reproduce the failure? There's much of overhead involved. Would be great if we can shrink it further to only guard against the purge case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed 2 lines, but it doesn't help much ;-).
I tried to follow user steps and I think it is minimal test case this way.

It would simplify if we create db with first version of structure.sql without all these steps, but I don't how to do that in this test.

…ure schema format.

Additionally:
* It changes `purge` task on `sqlite3` adapter to recreate database file, to
be consistent with other adapters.
* Adds `purge` step when loading from `schema.rb`
@senny senny merged commit ad42aae into rails:master Jun 12, 2014
senny added a commit that referenced this pull request Jun 12, 2014
…-schema-for-sql-format

ActiveRecord::Migration.maintain_test_schema! doesn't work with structure.sql

Conflicts:
	activerecord/CHANGELOG.md
@senny
Copy link
Member

senny commented Jun 12, 2014

@morgoth thank you, this will solve my issues with foreign keys and makes the automatic schema maintenance more predictable.

It will add ~100ms penalty when running the tests and the schema migration needs to be performed. As this only happens here and then I don't think this is a big issue.

@rafaelfranca I'd like to backport this patch as is. This means the behavior for schema.rb would change as well. As foreign keys are coming with 4.2 this is not strictly required with 4.1. However I do think that it should work the same way wether you are using schema.rb or structure.sql.

@morgoth morgoth deleted the fix-automatic-maintaining-test-schema-for-sql-format branch June 12, 2014 13:42
@rafaelfranca
Copy link
Member

@senny 👍 for backporting to 4-1-stable as it is. @carlosantoniodasilva will be happy 😄

senny added a commit that referenced this pull request Jun 14, 2014
…-schema-for-sql-format

ActiveRecord::Migration.maintain_test_schema! doesn't work with structure.sql

Conflicts:
	activerecord/CHANGELOG.md

Conflicts:
	activerecord/CHANGELOG.md
@dhh
Copy link
Member

dhh commented Jun 29, 2014

This PR breaks rake db:schema:load for MySQL for development and production. I will revert for now.

dhh pushed a commit that referenced this pull request Jun 29, 2014
…ing-test-schema-for-sql-format"

This reverts commit 22e9a91. See discussion on 22e9a91 for details.

Conflicts:
	activerecord/CHANGELOG.md
@senny
Copy link
Member

senny commented Jul 2, 2014

@jonleighton might know what's going on. While thinking about it, this could also be related to spring. (just guessing though).

rafaelfranca added a commit to rafaelfranca/omg-rails that referenced this pull request Jul 2, 2014
…ntaining-test-schema-for-sql-format"

This reverts commit 46139d3, reversing
changes made to 8f24787.

Conflicts:
	activerecord/CHANGELOG.md
rafaelfranca added a commit to rafaelfranca/omg-rails that referenced this pull request Jul 2, 2014
…atic-maintaining-test-schema-for-sql-format""

This reverts commit 5c87b5c.
@jonleighton
Copy link
Member

I don't know sorry. You can exclude spring by setting the DISABLE_SPRING env var.

senny added a commit that referenced this pull request Jul 24, 2014
Previously this method always established a connection to the test database.
This resulted in buggy behavior when combined with other tasks like
`bin/rake db:schema:load`.

This was one of the reasons why #15394 (22e9a91)
was reverted:

> I’ve replicated it on a new app by the following commands: 1) rails
  generate model post:title, 2) rake db:migrate, 3) rake
  db:schema:load, 4) rails runner ‘puts Post.first’. The last command
  goes boom. Problem is that rake db:schema:load wipes the database,
  and then doesn’t actually restore it. This is all on MySQL. There’s
  no problem with SQLite.

  -- DHH

22e9a91#commitcomment-6834245
senny added a commit that referenced this pull request Jul 25, 2014
…maintaining-test-schema-for-sql-format""

This reverts commit 5c87b5c.
senny added a commit that referenced this pull request Jul 28, 2014
The rake tasks and the `DatabaseTakss` adapter classes used to
assume a configuration at some places. This forced the rake
tasks to establish a specific connection before calling into
`load_schema`.

After #15394 this started to cause issues because it could
`purge` the wrong database before loading the schema.
senny added a commit that referenced this pull request Aug 5, 2014
…maintaining-test-schema-for-sql-format""

This reverts commit 5c87b5c.
senny added a commit that referenced this pull request Aug 5, 2014
The rake tasks and the `DatabaseTakss` adapter classes used to
assume a configuration at some places. This forced the rake
tasks to establish a specific connection before calling into
`load_schema`.

After #15394 this started to cause issues because it could
`purge` the wrong database before loading the schema.
senny added a commit that referenced this pull request Aug 6, 2014
…maintaining-test-schema-for-sql-format""

This reverts commit 5c87b5c.
senny added a commit that referenced this pull request Aug 6, 2014
The rake tasks and the `DatabaseTakss` adapter classes used to
assume a configuration at some places. This forced the rake
tasks to establish a specific connection before calling into
`load_schema`.

After #15394 this started to cause issues because it could
`purge` the wrong database before loading the schema.
@jaredbeck
Copy link
Contributor

@senny This will be fixed in 4.2?

Here's a workaround for postgres users who want to use maintain_test_schema! in the meantime.

# Put in spec_helper, before call to ActiveRecord::Migration.maintain_test_schema!
if ActiveRecord::Migrator.needs_migration?
  puts('Needs migrations, purging test database ..')
  ActiveRecord::Tasks::PostgreSQLDatabaseTasks
    .new(ActiveRecord::Base.configurations.fetch('test'))
    .purge
end

@senny
Copy link
Member

senny commented Aug 15, 2014

@jaredbeck yes, this is fixed on master and will be released in 4.2

johncarney referenced this pull request in grosser/parallel_tests Aug 19, 2014
senny added a commit that referenced this pull request Aug 27, 2014
Previously this method always established a connection to the test database.
This resulted in buggy behavior when combined with other tasks like
`bin/rake db:schema:load`.

This was one of the reasons why #15394 (22e9a91)
was reverted:

> I’ve replicated it on a new app by the following commands: 1) rails
  generate model post:title, 2) rake db:migrate, 3) rake
  db:schema:load, 4) rails runner ‘puts Post.first’. The last command
  goes boom. Problem is that rake db:schema:load wipes the database,
  and then doesn’t actually restore it. This is all on MySQL. There’s
  no problem with SQLite.

  -- DHH

22e9a91#commitcomment-6834245

Conflicts:
	activerecord/CHANGELOG.md
@metaskills
Copy link
Contributor

Watching this issue... in v4.2.0.beta2 I have noticed that my test db never get's populated due to maintain_test_schema! calling load_schema_if_pending! and in my situation that returns false because I have an empty db/migrate directory even tho I have a valid schema.rb and dev structure. Not sure if pending migrations should be the only method that tells if you need a schema load for test env?

calebhearth added a commit to calebhearth/rails that referenced this pull request Dec 4, 2014
All of the behavior :environment was giving (that db:schema:load needed)
was provided as well with :load_config.

This will address an issue introduced in
rails#15394. The fact that db:schema:load
now drops and creates the database causes the Octopus gem to have [an
issue](thiagopradi/octopus#273) during the drop
step for the test database (which wasn't happening in db:schema:load
before). The error looks like:

    ActiveRecord::StatementInvalid: PG::ObjectInUse: ERROR:  cannot drop the currently open database
    : DROP DATABASE IF EXISTS "app_test"

Because of the timing, this issue is present in master, 4-2-*, and
4.1.8.

A note to forlorn developers who might see this: "Additionally" in a
commit message means you should have a separate commit, with a separate
justification for changes. Small commits with big messages are your
friends.
sgrif pushed a commit that referenced this pull request Dec 4, 2014
All of the behavior :environment was giving (that db:schema:load needed)
was provided as well with :load_config.

This will address an issue introduced in
#15394. The fact that db:schema:load
now drops and creates the database causes the Octopus gem to have [an
issue](thiagopradi/octopus#273) during the drop
step for the test database (which wasn't happening in db:schema:load
before). The error looks like:

    ActiveRecord::StatementInvalid: PG::ObjectInUse: ERROR:  cannot drop the currently open database
    : DROP DATABASE IF EXISTS "app_test"

Because of the timing, this issue is present in master, 4-2-*, and
4.1.8.

A note to forlorn developers who might see this: "Additionally" in a
commit message means you should have a separate commit, with a separate
justification for changes. Small commits with big messages are your
friends.
sivagollapalli pushed a commit to sivagollapalli/rails that referenced this pull request Dec 29, 2014
All of the behavior :environment was giving (that db:schema:load needed)
was provided as well with :load_config.

This will address an issue introduced in
rails#15394. The fact that db:schema:load
now drops and creates the database causes the Octopus gem to have [an
issue](thiagopradi/octopus#273) during the drop
step for the test database (which wasn't happening in db:schema:load
before). The error looks like:

    ActiveRecord::StatementInvalid: PG::ObjectInUse: ERROR:  cannot drop the currently open database
    : DROP DATABASE IF EXISTS "app_test"

Because of the timing, this issue is present in master, 4-2-*, and
4.1.8.

A note to forlorn developers who might see this: "Additionally" in a
commit message means you should have a separate commit, with a separate
justification for changes. Small commits with big messages are your
friends.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants