CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/metasploit/framework/spec/constants/suite.rb
Views: 1904
1
# Logs if constants created by module loading are left over after suite has completed.
2
module Metasploit::Framework::Spec::Constants::Suite
3
#
4
# CONSTANTS
5
#
6
7
LOGS_PATHNAME = Pathname.new('log/metasploit/framework/spec/constants/suite')
8
9
# Logs leaked constants to LOG_PATHNAME and prints `message` to stderr.
10
#
11
# @param hook (see log_pathname)
12
# @param message [String] additional message printed to stderr when there is at least one leaked constant.
13
# @return [void]
14
def self.log_leaked_constants(hook, message)
15
count = 0
16
hook_log_pathname = log_pathname(hook)
17
hook_log_pathname.parent.mkpath
18
19
hook_log_pathname.open('w') do |f|
20
count = Metasploit::Framework::Spec::Constants.each do |child_name|
21
f.puts child_name
22
end
23
end
24
25
if count > 0
26
$stderr.puts "#{count} #{'constant'.pluralize(count)} leaked under " \
27
"#{Metasploit::Framework::Spec::Constants::PARENT_CONSTANT}. #{message} See #{hook_log_pathname} " \
28
"for details."
29
else
30
hook_log_pathname.delete
31
end
32
end
33
34
# Configures after(:suite) callback for RSpec to check for leaked constants.
35
def self.configure!
36
unless @configured
37
RSpec.configure do |config|
38
config.before(:suite) do
39
Metasploit::Framework::Spec::Constants::Suite.log_leaked_constants(
40
:before,
41
'Modules are being loaded outside callbacks before suite starts.'
42
)
43
end
44
45
config.after(:suite) do
46
Metasploit::Framework::Spec::Constants::Suite.log_leaked_constants(
47
:after,
48
'Modules are being loaded inside callbacks or examples during suite run.'
49
)
50
end
51
end
52
53
@configured = true
54
end
55
end
56
57
# Adds action to `spec` task so that `rake spec` fails if `log/leaked-constants.log` exists after printing out the
58
# leaked constants.
59
#
60
# @return [void]
61
def self.define_task
62
Rake::Task.define_task(:spec) do
63
leaked_before = Metasploit::Framework::Spec::Constants::Suite.print_leaked_constants(:before)
64
leaked_after = Metasploit::Framework::Spec::Constants::Suite.print_leaked_constants(:after)
65
66
# leaks after suite can be be cleaned up by {Metasploit::Framework::Spec::Constants::Each.configure!}, but
67
# leaks before suite require user intervention to find the leaks since it's a programming error in how the specs
68
# are written where Modules are being loaded in the context scope.
69
if leaked_after
70
$stderr.puts
71
$stderr.puts "Add `Metasploit::Framework::Spec::Constants::Each.configure!` to `spec/spec_helper.rb` " \
72
"**NOTE: `Metasploit::Framework::Spec::Constants::Each` may report false leaks if `after(:all)` " \
73
"is used to clean up constants instead of `after(:each)`**"
74
end
75
76
if leaked_before || leaked_after
77
exit 1
78
end
79
end
80
end
81
82
# @param hook [:after, :before] Whether the log is recording leaked constants `:before` the suite runs or `:after` the
83
# suite runs.
84
def self.log_pathname(hook)
85
LOGS_PATHNAME.join("#{hook}.log")
86
end
87
88
# Prints logged leaked constants to stderr.
89
#
90
# @param hook [:after, :before] Whether the log is recording leaked constants `:before` the suite runs or `:after` the
91
# suite runs.
92
# @return [true] if leaks printed
93
# @return [false] otherwise
94
def self.print_leaked_constants(hook)
95
hook_log_pathname = log_pathname(hook)
96
97
leaks = false
98
99
if hook_log_pathname.exist?
100
leaks = true
101
$stderr.puts "Leaked constants detected under #{Metasploit::Framework::Spec::Constants::PARENT_CONSTANT} #{hook} suite:"
102
103
hook_log_pathname.open do |f|
104
f.each_line do |line|
105
constant_name = line.strip
106
full_name = Metasploit::Framework::Spec::Constants.full_name(constant_name)
107
108
if full_name
109
formatted_full_name = " # #{full_name}"
110
end
111
112
$stderr.puts " #{constant_name}#{formatted_full_name}"
113
end
114
end
115
end
116
117
leaks
118
end
119
end
120
121