Skip to content

Spec load order: no-op install_gem_requirements stub in login_helpers_spec breaks FFI for later spec files #1542

Description

@simtel12

Summary

Running these two spec files together fails to load, before any example runs:

bundle exec rspec spec/lib/common/authentication/login_helpers_spec.rb \
                  spec/lib/common/session_launcher_spec.rb
An error occurred while loading ./spec/lib/common/session_launcher_spec.rb.
Failure/Error: extend FFI::Library

NameError:
  uninitialized constant Lich::Common::GUI::WindowsCredentialManager::FFI
# ./lib/common/gui/windows_credential_manager.rb:16:in '<module:WindowsCredentialManager>'
...
# ./lib/common/gui_login.rb:5:in '<top (required)>'
# ./spec/login_spec_helper.rb:127:in '<top (required)>'
# ./spec/lib/common/session_launcher_spec.rb:1:in '<top (required)>'

0 examples, 0 failures, 1 error occurred outside of examples.

Scope

  • Order-dependent: spec/lib/common/session_launcher_spec.rb on its own passes.
  • The full suite is unaffectedbundle exec rspec is green (6292 examples, 0
    failures), so CI never sees this. It only bites when running a subset by hand,
    which is the normal loop while working on either file.
  • Not a regression from any particular change; reproduces on current main content.
    I hit it on a branch, then confirmed it at the branch point with nothing applied.

Root cause

Two competing stubs of Lich::Util.install_gem_requirements, each guarded so
whichever loads first wins and the other backs off:

  • spec/lib/common/authentication/login_helpers_spec.rb:19-25 defines a no-op
    version, guarded unless defined?(Lich::Util).
  • spec/login_spec_helper.rb:34-40 defines a version that actually does
    require 'os' and require 'ffi', guarded
    unless respond_to?(:install_gem_requirements).

When login_helpers_spec.rb loads first, the no-op wins, so login_spec_helper.rb
declines to replace it. login_spec_helper.rb:127 then requires gui_login.rb,
which pulls in lib/common/gui/windows_credential_manager.rb. That file's line 3
calls Lich::Util.install_gem_requirements({ 'ffi' => true }) — now a no-op — so
ffi is never required, and extend FFI::Library on line 16 raises.

Verified directly: after loading login_helpers_spec.rb alone,
Lich::Util.respond_to?(:install_gem_requirements) is true while neither
lib/util/util.rb nor ffi is in $LOADED_FEATURES.

Possible fixes

  1. Have spec/login_spec_helper.rb do its require 'ffi' / require 'os'
    unconditionally rather than only as a side effect of defining the stub, so it
    no longer matters who defined the method first.
  2. Or drop the ad-hoc stub in login_helpers_spec.rb and let the shared helper own it.
  3. Independently of the spec plumbing: windows_credential_manager.rb does
    extend FFI::Library at module-body level on every platform, but only calls
    ffi_lib inside if OS.windows?. Guarding the extend the same way would make
    the file inert off-Windows and remove the load-order dependency entirely.

Happy to put up a PR for whichever of these you'd prefer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions