Class: Puppet::Test::TestHelper
- Defined in:
- lib/puppet/test/test_helper.rb
Overview
This class is intended to provide an API to be used by external projects
when they are running tests that depend on puppet core. This should
allow us to vary the implementation details of managing puppet's state
for testing, from one version of puppet to the next--without forcing
the external projects to do any of that state management or be aware of
the implementation details.
For now, this consists of a few very simple signatures. The plan is
that it should be the responsibility of the puppetlabs_spec_helper
to broker between external projects and this API; thus, if any
hacks are required (e.g. to determine whether or not a particular)
version of puppet supports this API, those hacks will be consolidated in
one place and won't need to be duplicated in every external project.
This should also alleviate the anti-pattern that we’ve been following,
wherein each external project starts off with a copy of puppet core's
test_helper.rb and is exposed to risk of that code getting out of
sync with core.
Since this class will be “library code” that ships with puppet, it does
not use API from any existing test framework such as rspec. This should
theoretically allow it to be used with other unit test frameworks in the
future, if desired.
Note that in the future this API could potentially be expanded to handle
other features such as "around_test", but we didn't see a compelling
reason to deal with that right now.
Constant Summary collapse
- ROLLBACK_MARK =
The name of the rollback mark used in the Puppet.context. This is what the test infrastructure returns to for each test.
"initial testing state"
Class Method Summary collapse
-
.after_all_tests ⇒ Object
Call this method once, at the end of a test run, when no more tests will be run.
-
.after_each_test ⇒ Object
Call this method once per test, after execution of each individual test.
-
.before_all_tests ⇒ Object
Call this method once, when beginning a test run–prior to running any individual tests.
-
.before_each_test ⇒ Object
Call this method once per test, prior to execution of each individual test.
-
.initialize ⇒ Object
Call this method once, as early as possible, such as before loading tests that call Puppet.
Class Method Details
.after_all_tests ⇒ Object
Call this method once, at the end of a test run, when no more tests
will be run.
77 78 |
# File 'lib/puppet/test/test_helper.rb', line 77 def self.after_all_tests() end |
.after_each_test ⇒ Object
Call this method once per test, after execution of each individual test.
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/puppet/test/test_helper.rb', line 151 def self.after_each_test() # Ensure that a matching tear down only happens once per completed setup # (see #before_each_test). return unless @@reentry_count == 1 @@reentry_count = 0 Puppet.settings.send(:clear_everything_for_tests) Puppet::Util::Storage.clear Puppet::Util::ExecutionStub.reset Puppet.clear_deprecation_warnings # uncommenting and manipulating this can be useful when tracking down calls to deprecated code #Puppet.log_deprecations_to_file("deprecations.txt", /^Puppet::Util.exec/) # Restore the indirector configuration. See before hook. indirections = Puppet::Indirector::Indirection.send(:class_variable_get, :@@indirections) indirections.each do |indirector| $saved_indirection_state.fetch(indirector.name, {}).each do |variable, value| indirector.instance_variable_set(variable, value) end end $saved_indirection_state = nil # Can't use Puppet.features.microsoft_windows? as it may be mocked out in a test. This can cause test recurring test failures if (!!File::ALT_SEPARATOR) mode = :windows else mode = :posix end # Restore the global process environment. Can't just assign because this # is a magic variable, sadly, and doesn't do that™. It is sufficiently # faster to use the compare-then-set model to avoid excessive work that it # justifies the complexity. --daniel 2012-03-15 unless Puppet::Util.get_environment(mode) == $old_env Puppet::Util.clear_environment(mode) $old_env.each {|k, v| Puppet::Util.set_env(k, v, mode) } end # Clear all environments Puppet.lookup(:environments).clear_all # Restore the load_path late, to avoid messing with stubs from the test. $LOAD_PATH.clear $old_load_path.each {|x| $LOAD_PATH << x } Puppet.rollback_context(ROLLBACK_MARK) end |
.before_all_tests ⇒ Object
Call this method once, when beginning a test run–prior to running
any individual tests.
70 71 72 |
# File 'lib/puppet/test/test_helper.rb', line 70 def self.before_all_tests() # Make sure that all of the setup is also done for any before(:all) blocks end |
.before_each_test ⇒ Object
Call this method once per test, prior to execution of each individual test.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/puppet/test/test_helper.rb', line 87 def self.before_each_test() # When using both rspec-puppet and puppet-rspec-helper, there are two packages trying # to be helpful and orchestrate the callback sequence. We let only the first win, the # second callback results in a no-op. # Likewise when entering after_each_test(), a check is made to make tear down happen # only once. # return unless @@reentry_count == 0 @@reentry_count = 1 Puppet.mark_context(ROLLBACK_MARK) # We need to preserve the current state of all our indirection cache and # terminus classes. This is pretty important, because changes to these # are global and lead to order dependencies in our testing. # # We go direct to the implementation because there is no safe, sane public # API to manage restoration of these to their default values. This # should, once the value is proved, be moved to a standard API on the # indirector. # # To make things worse, a number of the tests stub parts of the # indirector. These stubs have very specific expectations that what # little of the public API we could use is, well, likely to explode # randomly in some tests. So, direct access. --daniel 2011-08-30 $saved_indirection_state = {} indirections = Puppet::Indirector::Indirection.send(:class_variable_get, :@@indirections) indirections.each do |indirector| $saved_indirection_state[indirector.name] = { :@terminus_class => indirector.instance_variable_get(:@terminus_class), :@cache_class => indirector.instance_variable_get(:@cache_class) } end # The process environment is a shared, persistent resource. # Can't use Puppet.features.microsoft_windows? as it may be mocked out in a test. This can cause test recurring test failures if (!!File::ALT_SEPARATOR) mode = :windows else mode = :posix end $old_env = Puppet::Util.get_environment(mode) # So is the load_path $old_load_path = $LOAD_PATH.dup initialize_settings_before_each() Puppet.push_context( { :trusted_information => Puppet::Context::TrustedInformation.new('local', 'testing', {}), }, "Context for specs") Puppet::Parser::Functions.reset Puppet::Application.clear! Puppet::Util::Profiler.clear Puppet.clear_deprecation_warnings end |
.initialize ⇒ Object
Call this method once, as early as possible, such as before loading tests that call Puppet.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/puppet/test/test_helper.rb', line 36 def self.initialize() # This meta class instance variable is used as a guard to ensure that # before_each, and after_each are only called once. This problem occurs # when there are more than one puppet test infrastructure orchestrator in use. # The use of both puppetabs-spec_helper, and rodjek-rspec_puppet will cause # two resets of the puppet environment, and will cause problem rolling back to # a known point as there is no way to differentiate where the calls are coming # from. See more information in #before_each_test, and #after_each_test # Note that the variable is only initialized to 0 if nil. This is important # as more than one orchestrator will call initialize. A second call can not # simply set it to 0 since that would potentially destroy an active guard. # @@reentry_count ||= 0 @environmentpath = Dir.mktmpdir('environments') Dir.mkdir("#{@environmentpath}/production") owner = Process.pid Puppet.push_context(Puppet.base_context({ :environmentpath => @environmentpath, :basemodulepath => "", }), "Initial for specs") Puppet::Parser::Functions.reset ObjectSpace.define_finalizer(Puppet.lookup(:environments), proc { if Process.pid == owner FileUtils.rm_rf(@environmentpath) end }) Puppet::SSL::Oids.register_puppet_oids end |