pseudo_cleaner 0.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ N2YxYjQzYTAzZDJkN2M0YzQ0YjE1ODgwMjA3Y2ZlYWNiNTQzNTk4NQ==
5
+ data.tar.gz: !binary |-
6
+ ZGI3ODU3NGEyOTE5NGUxODBhNjhlMjk2MTM3ODA5OGZjZDA3NzU4ZQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MDUxNTk3ZDNiM2RlZDJmYzM5NGRlZjhhMzQ5Yjg1YWY4OTE2MmQ5ZWY1ZWVj
10
+ MTM2MGM0MzQ3MTNkYWIxNDQyYjUxZGQ1OTVkYTg5YjJmNTQ1ZTk2MmExNmNj
11
+ YzY1MWE5ZjdkMWY3YmMxNjQ1ODgxYmQxNzQ0ZGM4OWIyYzMzZmM=
12
+ data.tar.gz: !binary |-
13
+ NzBlNGYwNmU4ZTA0MDM4MzA3YTRjYjI4NzY4YTJlZTk1YjJhMTM2ZjA3YjUw
14
+ MjlmMDUyNzZlNzI2NmE4ZGUyNDQ5ODBlNjM5NDEyNGQwMzMwYzc2ODk1Zjk5
15
+ NjRhY2VhNTdlM2RmNWNmYjQ2MGZhOGI1NmIyY2EwMWVlMmMwMmM=
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ .idea/
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pseudo_cleaner.gemspec
4
+ gemspec
5
+
6
+ gem "gem-release"
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 RealNobody
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # PseudoCleaner
2
+
3
+ The [Database Cleaner gem](https://github.com/DatabaseCleaner/database_cleaner) is a wonderful tool,
4
+ and I've used it for years. I would highly recommend it. It is a well written and a well used and therefore tested
5
+ tool that you can rely on.
6
+
7
+ However, it is (quite rightly) a very conservative tool. I often run into situations where it doesn't quite fit my
8
+ needs. there are often times when I cannot use transactions (such as when I am doing Cucumber tests with Capybara to
9
+ feature test my site), but when truncating my tables just isn't reasonable or practical.
10
+
11
+ So, I came up with a compromise that works for a large number of tables and databases that I've worked with. The
12
+ thing is that this solution is not like DatabaseCleaner in that it isn't conservative,
13
+ and it doesn't guarantee much. This solution might not clean the database entirely between calls.
14
+
15
+ The thing is, the database doesn't have to be entirely clean after every call for most tests,
16
+ just clean enough is often good enough.
17
+
18
+ So, what is it that the PseudoCleaner does and why is it good enough?
19
+
20
+ The cleaner relies on the fact that most databases use 2 common defaults in most tables (well,
21
+ most tables that simple tests that rely on the workings of a cleaner anyway...) Those features are an auto-increment
22
+ `id` column, and/or a `created_at`/`updated_at` columns.
23
+
24
+ Using these, when a test starts the cleaner iterates through the tables and saves the current `MAX(id)`,
25
+ `MAX(created_at)`, and `MAX(updated_at)` values for a table. When a test ends, the cleaner iterates through the
26
+ tables again and deletes anything that is new. It will then report (optionally) on any records that have been
27
+ updated but haven't been cleaned up. In future versions, I have plans for it to also report (optionally) on any
28
+ referential integrity holes.
29
+
30
+ Because the PsuedoCleaner already uses the [SortedSeeder gem](https://github.com/RealNobody/sorted_seeder) to determine what
31
+ order to delete records in when cleaning up, when the database is truncated, it will re-seed the database using the
32
+ SortedSeeders seed_all function.
33
+
34
+ ## Installation
35
+
36
+ Add this line to your application's Gemfile in the test group:
37
+
38
+ gem 'pseudo_cleaner'
39
+
40
+ OR
41
+
42
+ gem 'pseudo_cleaner', '~> 0.0.1', :git => "git@github.com/RealNobody/pseudo_cleaner.git"
43
+
44
+ And then execute:
45
+
46
+ $ bundle
47
+
48
+ Or install it yourself as:
49
+
50
+ $ gem install pseudo_cleaner
51
+
52
+ ## Usage
53
+
54
+ There are multiple ways to use the PseudoCleaner. The main intended usages are detailed here:
55
+
56
+ ### Rspec
57
+
58
+ Rspect integration is built in to make using the PseudoCleaner simple and straight-forward.
59
+ To integrate the PseudoCleaner with Rspec, simply add the following lines to `spec_helper.rb`:
60
+
61
+ require 'pseudo_cleaner'
62
+ require 'pseudo_cleaner/rspec'
63
+
64
+ All tests will now by default use DatabaseCleaner with the `:transaction` strategy. For most tests, this will wrap
65
+ the test in a transaction, and roll back the transaction at the end of the test.
66
+
67
+ If a test is a feature test which uses Capybara using the `:js` tag, that test will be switched to not use
68
+ DatabaseCleaner. Instead, the test will use the `:pseudo_delete` strategy which as described will store the state of
69
+ the tables before the test then delete any new records at the end of the test.
70
+
71
+ If you want or need a specific strategy for a single test, you can specify the metadata tag: `:strategy` in the test
72
+ to change the behavior of the test. This tag accepts the following values:
73
+
74
+ * :none - Do not use any cleaning on this test run.
75
+ * :psedu_delete - Do not use DatabaseCleaner and clean tables individually.
76
+ * :truncation - Use the :truncation strategy with DatabaseCleaner and re-seed the database after truncation.
77
+ * :deletion - Use the :deletion strategy with DatabaseCleaner and re-seed the database after deletion.
78
+ * :transaction - Use the :transaction strategy with DatabaseCleaner.
79
+
80
+ Example:
81
+
82
+ it "is a test", strategy: :truncation do
83
+ expect(something).to work
84
+ end
85
+
86
+ ### Cucumber
87
+
88
+ Cucumber integration similar to Rspec integration is planned, but not implemented yet.
89
+
90
+ ### Manual
91
+
92
+ There are two ways to use the cleaner manually. When you use the cleaner manually, you are only using the
93
+ PseduoCleaner. You do not get DatabaseCleaner integration like you get automatically with Rspec. This will create
94
+ table cleaners and any custom defined cleaners and execute them.
95
+
96
+ NOTE: When using the tool manually, if the strategy is any strategy other than `:pseudo_delete`, the default
97
+ cleaners will not do anything. The strategy may still be useful though if you have any custom cleaners.
98
+
99
+ *PseudoCleaner::MasterCleaner.clean* This function cleans the code executed inside a block and takes two parameters.
100
+ The first parameter takes the values `:test` or `:suite`. This is used to determine if the cleaner is wrapped around
101
+ a set of tests or a single test. The default implementations provided do not distinguish between these, but custom
102
+ cleaners might. The second parameter is the strategy to use.
103
+
104
+ PseudoCleaner::MasterCleaner.clean(:test, :pseudo_delete) do
105
+ # Your code here
106
+ end
107
+
108
+ *PseudoCleaner::MasterCleaner.start_test* This takes one parameter that is the type of the cleaner this is (`:test` or
109
+ `:suite`). This creates a cleaner object that can be started and ended around the code to be cleaned. You specify
110
+ the strategy for the tests when you start the cleaner.
111
+
112
+ pseudo_cleaner = PseudoCleaner::MasterCleaner.start_test :pseudo_delete
113
+ # Your code here
114
+ pseudo_cleaner.end
115
+
116
+ ## Custom Cleaners
117
+
118
+ This system is built to clean the database after calls.
119
+
120
+ If you have additional actions which need to be done either before and/or after tests run to clean up resources, you
121
+ can create custom cleaners and place them in the `db/cleaners` folder. You can also create a custom cleaner for a
122
+ specific table by placing the cleaner in the same folder and naming it `<TableName>Cleaner`.
123
+
124
+ Cleaners must be instantiated, and will be initialized with the following prototype:
125
+ `initialize(start_method, end_method, table, options = {})`
126
+
127
+ Cleaners must also include one or more of the following funcitons:
128
+
129
+ * test_start test_strategy
130
+ * test_end test_strategy
131
+ * suite_start test_strategy
132
+ * suite_end test_strategy
133
+
134
+ A Cleaner can adjust when it is called in relation to other cleaners by overriding the instance method `<=>`
135
+
136
+ ## Contributing
137
+
138
+ 1. Fork it
139
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
140
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
141
+ 4. Push to the branch (`git push origin my-new-feature`)
142
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,12 @@
1
+ require "sorted_seeder"
2
+ require "colorize"
3
+ require "database_cleaner"
4
+ require "pseudo_cleaner/version"
5
+ require "pseudo_cleaner/configuration"
6
+ require "pseudo_cleaner/table_cleaner"
7
+ require "pseudo_cleaner/master_cleaner"
8
+ require "pseudo_cleaner/logger"
9
+
10
+ module PseudoCleaner
11
+ # Your code goes here...
12
+ end
@@ -0,0 +1,44 @@
1
+ module PseudoCleaner
2
+ class Configuration
3
+ @@current_instance = nil
4
+
5
+ # A simple configuration class for the PseudoCleaner
6
+ #
7
+ # Configurations:
8
+ # output_diagnostics - true/false
9
+ # if true, the system will use puts to output information about what it is doing...
10
+ attr_accessor :output_diagnostics
11
+ attr_accessor :clean_database_before_tests
12
+ attr_accessor :reset_auto_increment
13
+ attr_accessor :single_cleaner_set
14
+ attr_accessor :post_transaction_analysis
15
+
16
+ def self.current_instance
17
+ @@current_instance ||= PseudoCleaner::Configuration.new
18
+ end
19
+
20
+ def initialize
21
+ @output_diagnostics = false # false to keep the noise level down...
22
+ @clean_database_before_tests = false # false because I think it will annoy developers...
23
+ @reset_auto_increment = true # true because I think it should be done
24
+ @single_cleaner_set = true # true because I hope it will improve performance
25
+ @post_transaction_analysis = false # should only be set true if you are searching for a problem
26
+ end
27
+
28
+ def self.db_connection=(connection)
29
+ @db_connection = connection
30
+ end
31
+
32
+ def self.db_connection(type)
33
+ if @db_connection || type.nil?
34
+ @db_connection
35
+ else
36
+ if type == :sequel
37
+ Sequel::DATABASES[0]
38
+ else
39
+ ActiveRecord::Base
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ first_test_run = false
2
+
3
+ # turn off Cucumber's default usage of DatabaseCleaner
4
+ Cucumber::Rails::Database.autorun_database_cleaner = false
5
+
6
+ Before do |scenario|
7
+ unless first_test_run
8
+ first_test_run = true
9
+ # before tests run...
10
+ # We start suite in case a custom cleaner wants/needs to.
11
+ if PseudoCleaner::Configuration.current_instance.clean_database_before_tests
12
+ PseudoCleaner::MasterCleaner.reset_database
13
+ else
14
+ PseudoCleaner::MasterCleaner.start_suite
15
+ end
16
+
17
+ DatabaseCleaner.strategy = :transaction
18
+ end
19
+ end
20
+
21
+ Before("~@truncation", "~@deletion") do |scenario|
22
+ PseudoCleaner::MasterCleaner.start_example(scenario, :pseudo_delete)
23
+ end
24
+
25
+ Before("@truncation") do |scenario|
26
+ PseudoCleaner::MasterCleaner.start_example(scenario, :truncation)
27
+ end
28
+
29
+ Before("@deletion", "~@truncation") do |scenario|
30
+ PseudoCleaner::MasterCleaner.start_example(scenario, :deletion)
31
+ end
32
+
33
+ Before("@none") do |scenario|
34
+ PseudoCleaner::MasterCleaner.start_example(scenario, :none)
35
+ end
36
+
37
+ After do |scenario|
38
+ PseudoCleaner::MasterCleaner.end_example(scenario)
39
+ end
40
+
41
+ at_exit do
42
+ # We end suite in case a custom cleaner wants/needs to.
43
+ PseudoCleaner::MasterCleaner.end_suite
44
+ end
@@ -0,0 +1,9 @@
1
+ module PseudoCleaner
2
+ class Logger
3
+ class << self
4
+ def write(log_output)
5
+ puts(log_output)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,380 @@
1
+ require "sorted_seeder"
2
+
3
+ module PseudoCleaner
4
+ class MasterCleaner
5
+ @@suite_cleaner = nil
6
+ @@cleaner_classes = nil
7
+ @@cleaner_classes_sorted = false
8
+
9
+ CLEANING_STRATEGIES = [:transaction, :truncation, :deletion, :pseudo_delete, :none]
10
+ DB_CLEANER_CLEANING_STRATEGIES =
11
+ {
12
+ transaction: :transaction,
13
+ truncation: :truncation,
14
+ deletion: :deletion,
15
+ pseudo_delete: :transaction
16
+ }
17
+ VALID_TEST_TYPES = [:suite, :test]
18
+
19
+ VALID_START_METHODS = [:test_start, :suite_start]
20
+ VALID_END_METHODS = [:test_end, :suite_end]
21
+ VALID_TEST_METHODS = VALID_START_METHODS + VALID_END_METHODS
22
+
23
+ class << self
24
+ def start_suite
25
+ if @@suite_cleaner
26
+ @@suite_cleaner.reset_suite
27
+ end
28
+ @@suite_cleaner = PseudoCleaner::MasterCleaner.new(:suite)
29
+ @@suite_cleaner.start :pseudo_delete
30
+ @@suite_cleaner
31
+ end
32
+
33
+ def start_example(example_class, strategy)
34
+ pseudo_cleaner_data = {}
35
+ pseudo_cleaner_data[:test_strategy] = strategy
36
+
37
+ unless strategy == :none
38
+ raise "invalid strategy" unless PseudoCleaner::MasterCleaner::DB_CLEANER_CLEANING_STRATEGIES.has_key? strategy
39
+
40
+ DatabaseCleaner.strategy = PseudoCleaner::MasterCleaner::DB_CLEANER_CLEANING_STRATEGIES[strategy]
41
+ unless [:pseudo_delete].include? strategy
42
+ if Object.const_defined?("ActiveRecord", false) && ActiveRecord.const_defined?("Base", false)
43
+ DatabaseCleaner[:active_record, connection: PseudoCleaner::Configuration.db_connection(:active_record)].
44
+ start
45
+ elsif Object.const_defined?("Sequel", false) && Sequel.const_defined?("Model", false)
46
+ DatabaseCleaner[:sequel, connection: PseudoCleaner::Configuration.db_connection(:sequel)].start
47
+ end
48
+ # DatabaseCleaner.start
49
+ end
50
+
51
+ pseudo_cleaner_data[:pseudo_state] = PseudoCleaner::MasterCleaner.start_test strategy
52
+ end
53
+
54
+ example_class.instance_variable_set(:@pseudo_cleaner_data, pseudo_cleaner_data)
55
+ end
56
+
57
+ def end_example(example_class)
58
+ pseudo_cleaner_data = example_class.instance_variable_get(:@pseudo_cleaner_data)
59
+
60
+ unless pseudo_cleaner_data[:test_strategy] == :none
61
+ unless [:pseudo_delete].include? pseudo_cleaner_data[:test_strategy]
62
+ if Object.const_defined?("ActiveRecord", false) && ActiveRecord.const_defined?("Base", false)
63
+ DatabaseCleaner[:active_record, connection: PseudoCleaner::Configuration.db_connection(:active_record)].
64
+ clean
65
+ elsif Object.const_defined?("Sequel", false) && Sequel.const_defined?("Model", false)
66
+ DatabaseCleaner[:sequel, connection: PseudoCleaner::Configuration.db_connection(:sequel)].clean
67
+ end
68
+ # DatabaseCleaner.clean
69
+ end
70
+
71
+ case pseudo_cleaner_data[:test_strategy]
72
+ when :deletion, :truncation
73
+ PseudoCleaner::MasterCleaner.database_reset
74
+ end
75
+
76
+ pseudo_cleaner_data[:pseudo_state].end test_type: :test, test_strategy: pseudo_cleaner_data[:test_strategy]
77
+ end
78
+ end
79
+
80
+ def end_suite
81
+ @@suite_cleaner.end test_strategy: :pseudo_delete if @@suite_cleaner
82
+ end
83
+
84
+ def start_test test_strategy
85
+ raise "Invalid test_strategy \"#{test_strategy}\"" unless CLEANING_STRATEGIES.include? test_strategy
86
+
87
+ cleaner = if PseudoCleaner::Configuration.current_instance.single_cleaner_set
88
+ @@suite_cleaner
89
+ else
90
+ PseudoCleaner::MasterCleaner.new(:test)
91
+ end
92
+
93
+ cleaner.start test_strategy, test_type: :test, test_strategy: test_strategy
94
+
95
+ cleaner
96
+ end
97
+
98
+ def clean(test_type, test_strategy, &block)
99
+ raise "Invalid test_type \"#{test_type}\"" unless [:suite, :test].include? test_type
100
+ raise "Invalid test_strategy \"#{test_strategy}\"" unless CLEANING_STRATEGIES.include? test_strategy
101
+
102
+ master_cleaner = PseudoCleaner::MasterCleaner.send "start_#{test_type}", test_strategy
103
+
104
+ body_error = nil
105
+ begin
106
+ block.yield master_cleaner
107
+ rescue => error
108
+ body_error = error
109
+ end
110
+
111
+ master_cleaner.end test_type: test_type, test_strategy: test_strategy
112
+
113
+ raise body_error if body_error
114
+ end
115
+
116
+ def reset_database
117
+ DatabaseCleaner.clean_with(:truncation)
118
+
119
+ PseudoCleaner::MasterCleaner.database_reset
120
+ end
121
+
122
+ def database_reset
123
+ PseudoCleaner::MasterCleaner.seed_data
124
+ PseudoCleaner::MasterCleaner.start_suite
125
+ end
126
+
127
+ def seed_data
128
+ PseudoCleaner::Logger.write("Re-seeding database".red.on_light_white)
129
+ SortedSeeder::Seeder.seed_all(PseudoCleaner::Configuration.db_connection(nil))
130
+ end
131
+
132
+ def process_exception(error)
133
+ PseudoCleaner::Logger.write(" An exception has occurred:".red.on_light_white)
134
+ PseudoCleaner::Logger.write("")
135
+ PseudoCleaner::Logger.write(error.to_s)
136
+ PseudoCleaner::Logger.write(error.backtrace.join("\n")) if error.backtrace
137
+ end
138
+
139
+ def cleaner_class(table_name)
140
+ seed_class_name = "#{table_name.to_s.classify}Cleaner"
141
+ seed_class_base_name = seed_class_name.demodulize
142
+ base_module = seed_class_name.split("::")[0..-2].join("::")
143
+ base_module_classes = [Object]
144
+
145
+ unless base_module.blank?
146
+ base_module_classes = base_module_classes.unshift base_module.constantize
147
+ end
148
+
149
+ return_class = nil
150
+ 2.times do
151
+ base_module_classes.each do |base_class|
152
+ if (base_class.const_defined?(seed_class_base_name, false))
153
+ if base_class == Object
154
+ return_class = seed_class_base_name.constantize
155
+ else
156
+ return_class = "#{base_class.name}::#{seed_class_base_name}".constantize
157
+ end
158
+
159
+ break
160
+ end
161
+ end
162
+
163
+ break if return_class
164
+
165
+ seeder_file = "db/cleaners/"
166
+ seeder_file += base_module.split("::").map { |module_name| module_name.underscore }.join("/")
167
+ seeder_file += "/" unless seeder_file[-1] == "/"
168
+ seeder_file += seed_class_base_name.underscore
169
+ seeder_file += ".rb"
170
+ seeder_file = File.join(Rails.root, seeder_file)
171
+
172
+ break unless File.exists?(seeder_file)
173
+
174
+ require seeder_file
175
+ end
176
+
177
+ # unless return_class &&
178
+ # VALID_TEST_METHODS.any? { |test_method| return_class.instance_methods.include?(test_method.to_sym) }
179
+ # return_class = table
180
+ # end
181
+
182
+ unless return_class &&
183
+ VALID_TEST_METHODS.any? { |test_method| return_class.instance_methods.include?(test_method.to_sym) }
184
+ return_class = PseudoCleaner::TableCleaner
185
+ end
186
+
187
+ return_class
188
+ end
189
+
190
+ def cleaner_classes
191
+ unless @@cleaner_classes
192
+ @@cleaner_classes = []
193
+
194
+ PseudoCleaner::MasterCleaner.create_table_cleaners
195
+ PseudoCleaner::MasterCleaner.create_custom_cleaners
196
+ end
197
+
198
+ @@cleaner_classes
199
+ end
200
+
201
+ def create_table_cleaners(options = {})
202
+ SortedSeeder::Seeder.create_order(PseudoCleaner::Configuration.db_connection(nil)).each do |table|
203
+ cleaner_class = PseudoCleaner::MasterCleaner.cleaner_class(table.name)
204
+ if cleaner_class
205
+ PseudoCleaner::MasterCleaner.cleaner_classes << [table, nil, cleaner_class]
206
+ end
207
+ end
208
+ if SortedSeeder::Seeder.respond_to?(:unclassed_tables)
209
+ SortedSeeder::Seeder.unclassed_tables(PseudoCleaner::Configuration.db_connection(nil)).each do |table_name|
210
+ cleaner_class = PseudoCleaner::MasterCleaner.cleaner_class(table_name)
211
+ if cleaner_class
212
+ PseudoCleaner::MasterCleaner.cleaner_classes << [nil, table_name, cleaner_class]
213
+ end
214
+ end
215
+ end
216
+ end
217
+
218
+ def create_custom_cleaners(options = {})
219
+ if Object.const_defined?("Rails", false)
220
+ cleaner_root = Rails.root.join("db/cleaners/").to_s
221
+ cleaner_files = Dir[Rails.root.join("db/cleaners/**/*.rb")]
222
+
223
+ cleaner_files.each do |cleaner_file|
224
+ class_name = File.basename(cleaner_file, ".rb").classify
225
+
226
+ check_class, full_module_name = find_file_class(cleaner_file, cleaner_root)
227
+ unless check_class && check_class.const_defined?(class_name, false)
228
+ require cleaner_file
229
+ check_class, full_module_name = find_file_class(cleaner_file, cleaner_root)
230
+ end
231
+
232
+ if check_class
233
+ full_module_name << class_name
234
+ if check_class.const_defined?(class_name, false)
235
+ check_class = full_module_name.join("::").constantize
236
+ else
237
+ check_class = nil
238
+ end
239
+ end
240
+
241
+ if check_class &&
242
+ PseudoCleaner::MasterCleaner::VALID_TEST_METHODS.
243
+ any? { |test_method| check_class.instance_methods.include?(test_method) }
244
+ unless PseudoCleaner::MasterCleaner.cleaner_classes.any? { |cleaner| check_class == cleaner[2] }
245
+ PseudoCleaner::MasterCleaner.cleaner_classes << [nil, nil, check_class]
246
+ end
247
+ end
248
+ end
249
+ end
250
+ end
251
+
252
+ def find_file_class(seeder_file, seeder_root)
253
+ check_class = Object
254
+ full_module_name = []
255
+
256
+ File.dirname(seeder_file.to_s[seeder_root.length..-1]).split("/").map do |module_element|
257
+ if (module_element != ".")
258
+ full_module_name << module_element.classify
259
+ if check_class.const_defined?(full_module_name[-1], false)
260
+ check_class = full_module_name.join("::").constantize
261
+ else
262
+ check_class = nil
263
+ break
264
+ end
265
+ end
266
+ end
267
+
268
+ return check_class, full_module_name
269
+ end
270
+
271
+ def review_rows(&block)
272
+ @@suite_cleaner.review_rows &block
273
+ end
274
+ end
275
+
276
+ def initialize(test_type)
277
+ raise "Invalid test type. Must be one of: #{VALID_TEST_TYPES}" unless VALID_TEST_TYPES.include?(test_type)
278
+
279
+ @test_type = test_type
280
+ end
281
+
282
+ def start(test_strategy, options = {})
283
+ test_type = options[:test_type] || @test_type
284
+
285
+ unless @cleaners
286
+ @cleaners = []
287
+ @test_strategy = test_strategy
288
+
289
+ start_method = "#{test_type}_start".to_sym
290
+ end_method = "#{test_type}_end".to_sym
291
+
292
+ PseudoCleaner::MasterCleaner.cleaner_classes.each do |clean_class|
293
+ table = clean_class[0]
294
+ table ||= clean_class[1]
295
+
296
+ begin
297
+ @cleaners << clean_class[2].new(start_method, end_method, table, options)
298
+ rescue Exception => error
299
+ puts error.to_s
300
+ raise error
301
+ end
302
+ end
303
+
304
+ unless @@cleaner_classes_sorted
305
+ seed_sorts = @cleaners.map { |cleaner| SortedSeeder::Seeder::SeederSorter.new(cleaner) }
306
+ seed_sorts.sort!
307
+
308
+ @cleaners = seed_sorts.map(&:seed_base_object)
309
+
310
+ sorted_classes = []
311
+ @cleaners.each do |cleaner|
312
+ cleaner_class = PseudoCleaner::MasterCleaner.cleaner_classes.detect do |unsorted_cleaner|
313
+ if cleaner.class == unsorted_cleaner[2]
314
+ if unsorted_cleaner[2] == PseudoCleaner::TableCleaner
315
+ cleaner.table == unsorted_cleaner[0] || cleaner.table == unsorted_cleaner[1]
316
+ else
317
+ true
318
+ end
319
+ end
320
+ end
321
+
322
+ sorted_classes << cleaner_class
323
+ end
324
+
325
+ @@cleaner_classes = sorted_classes
326
+ @@cleaner_classes_sorted = true
327
+ end
328
+ end
329
+
330
+ start_all_cleaners options
331
+ end
332
+
333
+ def end(options = {})
334
+ test_type = options[:test_type] || @test_type
335
+ if PseudoCleaner::Configuration.current_instance.output_diagnostics ||
336
+ PseudoCleaner::Configuration.current_instance.post_transaction_analysis
337
+ PseudoCleaner::Logger.write("Cleaning #{test_type}")
338
+ end
339
+ end_all_cleaners options
340
+ end
341
+
342
+ def start_all_cleaners(options)
343
+ test_type = options[:test_type] || @test_type
344
+ test_strategy = options[:test_strategy] || @test_strategy
345
+ run_all_cleaners("#{test_type}_start".to_sym, @cleaners, test_strategy)
346
+ end
347
+
348
+ def end_all_cleaners(options)
349
+ test_type = options[:test_type] || @test_type
350
+ test_strategy = options[:test_strategy] || @test_strategy
351
+ run_all_cleaners("#{test_type}_end".to_sym, @cleaners.reverse, test_strategy)
352
+ end
353
+
354
+ def reset_suite
355
+ run_all_cleaners(:reset_suite, @cleaners.reverse)
356
+ end
357
+
358
+ def run_all_cleaners(cleaner_function, cleaners, *args, &block)
359
+ last_error = nil
360
+
361
+ cleaners.each do |cleaner|
362
+ begin
363
+ if cleaner.respond_to?(cleaner_function)
364
+ cleaner.send(cleaner_function, *args, &block)
365
+ end
366
+ rescue => error
367
+ PseudoCleaner::MasterCleaner.process_exception(last_error) if last_error
368
+
369
+ last_error = error
370
+ end
371
+ end
372
+
373
+ raise last_error if last_error
374
+ end
375
+
376
+ def review_rows(&block)
377
+ run_all_cleaners(:review_rows, @cleaners, &block)
378
+ end
379
+ end
380
+ end