Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/metasploit/framework/spec/constants/suite.rb
Views: 11789
# Logs if constants created by module loading are left over after suite has completed.1module Metasploit::Framework::Spec::Constants::Suite2#3# CONSTANTS4#56LOGS_PATHNAME = Pathname.new('log/metasploit/framework/spec/constants/suite')78# Logs leaked constants to LOG_PATHNAME and prints `message` to stderr.9#10# @param hook (see log_pathname)11# @param message [String] additional message printed to stderr when there is at least one leaked constant.12# @return [void]13def self.log_leaked_constants(hook, message)14count = 015hook_log_pathname = log_pathname(hook)16hook_log_pathname.parent.mkpath1718hook_log_pathname.open('w') do |f|19count = Metasploit::Framework::Spec::Constants.each do |child_name|20f.puts child_name21end22end2324if count > 025$stderr.puts "#{count} #{'constant'.pluralize(count)} leaked under " \26"#{Metasploit::Framework::Spec::Constants::PARENT_CONSTANT}. #{message} See #{hook_log_pathname} " \27"for details."28else29hook_log_pathname.delete30end31end3233# Configures after(:suite) callback for RSpec to check for leaked constants.34def self.configure!35unless @configured36RSpec.configure do |config|37config.before(:suite) do38Metasploit::Framework::Spec::Constants::Suite.log_leaked_constants(39:before,40'Modules are being loaded outside callbacks before suite starts.'41)42end4344config.after(:suite) do45Metasploit::Framework::Spec::Constants::Suite.log_leaked_constants(46:after,47'Modules are being loaded inside callbacks or examples during suite run.'48)49end50end5152@configured = true53end54end5556# Adds action to `spec` task so that `rake spec` fails if `log/leaked-constants.log` exists after printing out the57# leaked constants.58#59# @return [void]60def self.define_task61Rake::Task.define_task(:spec) do62leaked_before = Metasploit::Framework::Spec::Constants::Suite.print_leaked_constants(:before)63leaked_after = Metasploit::Framework::Spec::Constants::Suite.print_leaked_constants(:after)6465# leaks after suite can be be cleaned up by {Metasploit::Framework::Spec::Constants::Each.configure!}, but66# leaks before suite require user intervention to find the leaks since it's a programming error in how the specs67# are written where Modules are being loaded in the context scope.68if leaked_after69$stderr.puts70$stderr.puts "Add `Metasploit::Framework::Spec::Constants::Each.configure!` to `spec/spec_helper.rb` " \71"**NOTE: `Metasploit::Framework::Spec::Constants::Each` may report false leaks if `after(:all)` " \72"is used to clean up constants instead of `after(:each)`**"73end7475if leaked_before || leaked_after76exit 177end78end79end8081# @param hook [:after, :before] Whether the log is recording leaked constants `:before` the suite runs or `:after` the82# suite runs.83def self.log_pathname(hook)84LOGS_PATHNAME.join("#{hook}.log")85end8687# Prints logged leaked constants to stderr.88#89# @param hook [:after, :before] Whether the log is recording leaked constants `:before` the suite runs or `:after` the90# suite runs.91# @return [true] if leaks printed92# @return [false] otherwise93def self.print_leaked_constants(hook)94hook_log_pathname = log_pathname(hook)9596leaks = false9798if hook_log_pathname.exist?99leaks = true100$stderr.puts "Leaked constants detected under #{Metasploit::Framework::Spec::Constants::PARENT_CONSTANT} #{hook} suite:"101102hook_log_pathname.open do |f|103f.each_line do |line|104constant_name = line.strip105full_name = Metasploit::Framework::Spec::Constants.full_name(constant_name)106107if full_name108formatted_full_name = " # #{full_name}"109end110111$stderr.puts " #{constant_name}#{formatted_full_name}"112end113end114end115116leaks117end118end119120121