Project

General

Profile

Bug #13574

Plugins with Setting subclasses raise super: no superclass method `load_defaults' error

Added by Dominic Cleal over 3 years ago. Updated about 1 year ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
Plugins-Engines
Target version:
Difficulty:
Triaged:
Bugzilla link:
Team Backlog:
Fixed in Releases:
Found in Releases:

Description

Plugins that add a Setting subclass and load it through an initialiser are failing to run tests, raising the following error during startup:

21:11:54 + bundle exec rake jenkins:unit TESTOPTS=-v
21:12:00 rm -rf jenkins/reports/unit/
21:12:03 DEPRECATION WARNING: You are using a deprecated behavior, it will be removed in version 1.13, 
21:12:03 Initializing plugins using :after => :finish_hook in your engine is deprecated. It delays the load of some assets in Sprockets. If you are the plugin author, please change your plugin engine initializer to use :before => :finisher_hook or after_initialize.  Affected initializer name is foreman_bootdisk.register_plugin. (called from each at /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/config/initializers/assets_paths.rb:10)
21:12:03 rake aborted!
21:12:03 NoMethodError: super: no superclass method `load_defaults' for #<Class:0x00000002d13e48>
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activerecord-4.1.5/lib/active_record/dynamic_matchers.rb:26:in `method_missing'
21:12:03 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/app/models/setting/general.rb:5:in `load_defaults'
21:12:03 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/config/initializers/foreman.rb:21:in `each'
21:12:03 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/config/initializers/foreman.rb:21:in `<top (required)>'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:241:in `load'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:241:in `block in load'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:232:in `load_dependency'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:241:in `load'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/engine.rb:648:in `block in load_config_initializer'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/notifications.rb:161:in `instrument'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/engine.rb:647:in `load_config_initializer'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/engine.rb:612:in `block (2 levels) in <class:Engine>'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/engine.rb:611:in `each'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/engine.rb:611:in `block in <class:Engine>'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/initializable.rb:30:in `instance_exec'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/initializable.rb:30:in `run'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/initializable.rb:55:in `block in run_initializers'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/initializable.rb:44:in `each'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/initializable.rb:44:in `tsort_each_child'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/initializable.rb:54:in `run_initializers'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/application.rb:300:in `initialize!'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/railtie.rb:194:in `public_send'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/railtie.rb:194:in `method_missing'
21:12:03 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/config/environment.rb:5:in `<top (required)>'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:247:in `require'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:247:in `block in require'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:232:in `load_dependency'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:247:in `require'
21:12:03 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/test/test_helper.rb:20:in `block in <top (required)>'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/spork-1.0.0rc4/lib/spork.rb:24:in `prefork'
21:12:03 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/test/test_helper.rb:9:in `<top (required)>'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:247:in `require'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:247:in `block in require'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:232:in `load_dependency'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:247:in `require'
21:12:03 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/test/unit/application_mailer_test.rb:1:in `<top (required)>'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:247:in `require'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:247:in `block in require'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:232:in `load_dependency'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:247:in `require'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/test_unit/sub_test_task.rb:114:in `block (3 levels) in define'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/test_unit/sub_test_task.rb:114:in `each'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/test_unit/sub_test_task.rb:114:in `block (2 levels) in define'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/test_unit/sub_test_task.rb:113:in `each'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/gems/railties-4.1.5/lib/rails/test_unit/sub_test_task.rb:113:in `block in define'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/bin/ruby_executable_hooks:15:in `eval'
21:12:03 /usr/local/rvm/gems/ruby-2.1.5@test_plugin_matrix-3/bin/ruby_executable_hooks:15:in `<main>'
21:12:03 Tasks: TOP => jenkins:unit => test:units
21:12:03 (See full trace by running task with --trace)

They all started failing between Jan 28, 2016 9:42 PM and Jan 31, 2016 3:54 AM. I can't narrow down any commit on Foreman develop that causes it, suggesting something external (like a gem). 1.10-stable seems unaffected.

It can be reproduced locally by deleting the test DB and running rake test.


Related issues

Related to Foreman - Bug #14954: Stop auditing the default field in settingsAssigned
Blocks Foreman - Refactor #13409: Remove maintain_test_schema! Rails initializerClosed2016-01-27

Associated revisions

Revision 683e3a06 (diff)
Added by Dominic Cleal over 3 years ago

fixes #13574 - remove DB access from Setting class scope

Plugins tend to register an initialiser before config/initializers/ to
require their own Setting subclasses. This loads them before
config/initializers/foreman.rb, which calls load_defaults on each known
Setting class. When loading Setting in a test environment or without a
database yet, the class was getting partially loaded once due to a DB
call in validates_lengths_from_database 0.4.0 and also in the audited
:only call.

When partially loaded, the Setting.load_defaults method wasn't defined,
so calling `super` from a subclass failed:

NoMethodError: super: no superclass method `load_defaults' for #&lt;Class:0x00000002d13e48&gt;
gems/activerecord-4.1.5/lib/active_record/dynamic_matchers.rb:26:in `method_missing'
app/models/setting/general.rb:5:in `load_defaults'

In vlfd 0.5.0, the DB call was removed and it failed on audited instead.
Changing the audited options prevents that DB call and so the class now
loads just once on both 0.4.0 and 0.5.0. This also removes the need
for the hack in plugin initialisers to check if Setting.table_exists?
before loading their subclass as class loading is reliable.

History

#1 Updated by Dominic Cleal over 3 years ago

validates_lengths_from_database was updated from 0.4.0 to 0.5.0 in that period (er, with a patch from me). Downgrading the gem fixes it, but I think it's probably a bug in Foreman. Probably doesn't affect 1.10-stable as Rails 3 initialisation is a bit different to 4.

#2 Updated by Dominic Cleal over 3 years ago

Plugins that are calling Setting.table_exists? during an initializer (that runs before config_initializers, i.e. test DB setup and config/initializers/foreman.rb) are causing the Setting class to get partially loaded.

On 0.4.0 it was luckily getting reloaded later somehow, but this was actually indicated in the logs (should be a clue that not all was right before either) because the constants are loaded twice:

21:45:42 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/app/models/setting.rb:7: warning: already initialized constant Setting::TYPES
21:45:42 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/app/models/setting.rb:7: warning: previous definition of TYPES was here
21:45:42 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/app/models/setting.rb:8: warning: already initialized constant Setting::FROZEN_ATTRS
21:45:42 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/app/models/setting.rb:8: warning: previous definition of FROZEN_ATTRS was here
21:45:42 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/app/models/setting.rb:9: warning: already initialized constant Setting::NONZERO_ATTRS
21:45:42 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/app/models/setting.rb:9: warning: previous definition of NONZERO_ATTRS was here
21:45:42 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/app/models/setting.rb:10: warning: already initialized constant Setting::BLANK_ATTRS
21:45:42 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/app/models/setting.rb:10: warning: previous definition of BLANK_ATTRS was here
21:45:42 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/app/models/setting.rb:11: warning: already initialized constant Setting::URI_ATTRS
21:45:42 /var/lib/workspace/workspace/test_plugin_matrix/database/sqlite3/ruby/2.1/slave/fast/foreman/app/models/setting.rb:11: warning: previous definition of URI_ATTRS was here

On 0.4.0 it was perhaps failing to load the class at first because validates_lengths_from_database was attempting to access the table and failing.

On 0.5.0, vlfd no longer does this, but the audited gem still does because we're using the audited :only option (with :except it doesn't). They're both accessing the non-existent DB, but now it's resulting in the Setting class only getting partially loaded and then not functioning properly later (and not being loaded twice either).

If the plugin setting initialisers were called between config/initializers/0_maintain_test_schema and foreman.rb then they'd probably load OK, but that's tricky to specify. A better API for registering settings classes might have helped.

Changing the audited call to avoid the DB call would let the class load reliably (e.g. use :except instead of :only). It also stops it getting partially loaded and would prevent the duplicate constant warnings on vlfd 0.4.0. It also means that plugins can still require_dependency on their Setting subclasses and they will safely load without Setting ever being half-loaded - they can even remove the Setting.table_exists? check from the initialiser I think.

#3 Updated by The Foreman Bot over 3 years ago

  • Status changed from Assigned to Ready For Testing
  • Pull request https://github.com/theforeman/foreman/pull/3159 added

#4 Updated by Dominic Cleal over 3 years ago

  • Blocks Refactor #13409: Remove maintain_test_schema! Rails initializer added

#5 Updated by Dominic Cleal over 3 years ago

  • Status changed from Ready For Testing to Closed
  • % Done changed from 0 to 100

#6 Updated by Dominic Cleal over 3 years ago

  • Related to Bug #14954: Stop auditing the default field in settings added

Also available in: Atom PDF