CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/metasploit/framework/spec/constants/each.rb
Views: 11789
1
# @note This should only temporarily be used in `spec/spec_helper.rb` when
2
# `Metasploit::Framework::Spec::Constants::Suite.configure!` detects a leak. Permanently having
3
# `Metasploit::Framework::Spec::Constants::Each.configure!` can lead to false positives when modules are purposely
4
# loaded in a `before(:all)` and cleaned up in a `after(:all)`.
5
#
6
# Fails example if it leaks module loading constants.
7
module Metasploit::Framework::Spec::Constants::Each
8
#
9
# CONSTANTS
10
#
11
12
LOG_PATHNAME = Pathname.new('log/metasploit/framework/spec/constants/each.log')
13
14
#
15
# Module Methods
16
#
17
18
class << self
19
attr_accessor :leaks_cleaned
20
end
21
22
# Is Metasploit::Framework::Spec::Constants::Each.configure! still necessary or should it be removed?
23
#
24
# @return [true] if {configure!}'s `before(:each)` cleaned up leaked constants
25
# @return [false] otherwise
26
def self.leaks_cleaned?
27
!!@leaks_cleaned
28
end
29
30
# Configures after(:each) callback for RSpe to fail example if leaked constants.
31
#
32
# @return [void]
33
def self.configure!
34
unless @configured
35
RSpec.configure do |config|
36
config.before(:each) do |example|
37
leaks_cleaned = Metasploit::Framework::Spec::Constants.clean
38
39
if leaks_cleaned
40
$stderr.puts "Cleaned leaked constants before #{example.metadata.full_description}"
41
end
42
43
# clean so that leaks from earlier example aren't attributed to this example
44
Metasploit::Framework::Spec::Constants::Each.leaks_cleaned ||= leaks_cleaned
45
end
46
47
config.after(:each) do |example|
48
child_names = Metasploit::Framework::Spec::Constants.to_enum(:each).to_a
49
50
if child_names.length > 0
51
lines = ['Leaked constants:']
52
53
child_names.sort.each do |child_name|
54
lines << " #{child_name}"
55
end
56
57
lines << ''
58
lines << "Add `include_context 'Metasploit::Framework::Spec::Constants cleaner'` to clean up constants from #{example.metadata.full_description}"
59
60
message = lines.join("\n")
61
62
# use caller metadata so that Jump to Source in the Rubymine RSpec running jumps to the example instead of
63
# here
64
fail RuntimeError, message, example.metadata[:caller]
65
end
66
end
67
68
config.after(:suite) do
69
if Metasploit::Framework::Spec::Constants::Each.leaks_cleaned?
70
if LOG_PATHNAME.exist?
71
LOG_PATHNAME.delete
72
end
73
else
74
LOG_PATHNAME.open('w') { |f|
75
f.puts "No leaks were cleaned by `Metasploit::Framework::Spec::Constants::Each.configured!`. Remove " \
76
"it from `spec/spec_helper.rb` so it does not interfere with contexts that persist loaded " \
77
"modules for entire context and clean up modules in `after(:all)`"
78
}
79
end
80
end
81
end
82
83
@configured = true
84
end
85
end
86
87
# Whether {configure!} was called
88
#
89
# @return [Boolean]
90
def self.configured?
91
!!@configured
92
end
93
94
# Adds action to `spec` task so that `rake spec` fails if configured! is unnecessary in `spec/spec_helper.rb` and
95
# should be removed
96
#
97
# @return [void]
98
def self.define_task
99
Rake::Task.define_task('metasploit:framework:spec:constant:each:clean') do
100
if LOG_PATHNAME.exist?
101
LOG_PATHNAME.delete
102
end
103
end
104
105
Rake::Task.define_task(spec: 'metasploit:framework:spec:constant:each:clean')
106
107
Rake::Task.define_task(:spec) do
108
if LOG_PATHNAME.exist?
109
LOG_PATHNAME.open { |f|
110
f.each_line do |line|
111
$stderr.write line
112
end
113
}
114
115
exit(1)
116
end
117
end
118
end
119
end
120
121