myronmarston-factory_data_preloader 0.4.3 → 0.5.0
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.
- data/CHANGELOG.rdoc +41 -0
- data/README.rdoc +28 -8
- data/VERSION.yml +2 -2
- data/lib/factory_data_preloader.rb +1 -0
- data/lib/factory_data_preloader/factory_data.rb +18 -47
- data/lib/factory_data_preloader/preloaded_data_hash.rb +53 -0
- data/lib/factory_data_preloader/preloader.rb +58 -25
- data/lib/factory_data_preloader/preloader_collection.rb +2 -2
- data/test/factory_data_test.rb +43 -60
- data/test/lib/models.rb +3 -0
- data/test/lib/schema.rb +6 -0
- data/test/preloaded_data_hash_test.rb +88 -0
- data/test/preloader_test.rb +53 -8
- data/test/test_helper.rb +5 -20
- metadata +5 -2
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
== 0.5.0 / 2009-07-07
|
2
|
+
|
3
|
+
* Added better error handling. The data[:key] = record form is deprecated in favor of data.add(:key) { record }.
|
4
|
+
* Allow preloaders to be redefined. This should make this more compatible with autotest.
|
5
|
+
|
6
|
+
== 0.4.3 / 2009-06-05
|
7
|
+
|
8
|
+
* Added shoulda and mocha development dependencies.
|
9
|
+
|
10
|
+
== 0.4.2 / 2009-06-02
|
11
|
+
|
12
|
+
* Raise an appropriate error when the developer tries to get a record for a preloader that was never run.
|
13
|
+
|
14
|
+
== 0.4.1 / 2009-06-01
|
15
|
+
|
16
|
+
* Updated documentation (Forgot to for the 0.4.0 release).
|
17
|
+
|
18
|
+
== 0.4.0 / 2009-06-01
|
19
|
+
|
20
|
+
* Added ability to only preload some of the types.
|
21
|
+
* During preloading, print to the console to indicate the records being preloaded and a benchmark.
|
22
|
+
|
23
|
+
== 0.3.2 / 2009-04-07
|
24
|
+
|
25
|
+
* Fixed a bug with the ordering of the dependent preloaders.
|
26
|
+
|
27
|
+
== 0.3.1 / 2009-03-30
|
28
|
+
|
29
|
+
* Updated documentation. (Forgot to for 0.3.0 release)
|
30
|
+
|
31
|
+
== 0.3.0 / 2009-03-30
|
32
|
+
|
33
|
+
* Added logic to auto load the factory_data files.
|
34
|
+
|
35
|
+
== 0.2.0 / 2009-03-30
|
36
|
+
|
37
|
+
* Added :depends_on option to the preloader, to force the preloaders to load in the correct order based on your foreign keys and table dependencies.
|
38
|
+
|
39
|
+
== 0.1.0 / 2009-03-30
|
40
|
+
|
41
|
+
* Initial release
|
data/README.rdoc
CHANGED
@@ -34,23 +34,23 @@ Define your preloaded data. FactoryData will automatically require test/factory
|
|
34
34
|
Define your data in these files like this:
|
35
35
|
|
36
36
|
FactoryData.preload(:users) do |data|
|
37
|
-
data
|
38
|
-
data
|
37
|
+
data.add(:thom) { User.create(:first_name => 'Thom', :last_name => 'York') }
|
38
|
+
data.add(:john) { User.create(:first_name => 'John', :last_name => 'Doe') }
|
39
39
|
end
|
40
40
|
|
41
41
|
FactoryData.preload(:posts, :depends_on => :users) do |data|
|
42
42
|
# note the use of the :depends_on option to force the users to be loaded first.
|
43
|
-
data
|
43
|
+
data.add(:tour) { FactoryData.users(:thom).posts.create(:title => 'Tour!', :body => 'Radiohead will tour soon.') }
|
44
44
|
end
|
45
45
|
|
46
46
|
FactoryData.preload(:some_other_posts, :model_class => Post, :depends_on => :users) do |data|
|
47
47
|
# note the use of the :model_class option when the model class cannot be inferred from the symbol.
|
48
|
-
data
|
48
|
+
data.add(:another_post) { Post.create(:user => FactoryData.users(:john), :title => 'Life is good') }
|
49
49
|
end
|
50
50
|
|
51
51
|
FactoryData.preload(:comments, :depends_on => [:users, :posts]) do |data|
|
52
52
|
# :depends_on lets you pass an array
|
53
|
-
data
|
53
|
+
data.add(:woohoo) { FactoryData.users(:john).comments.create(:post => FactoryData.posts(:tour), :comment => "I can't wait!") }
|
54
54
|
end
|
55
55
|
|
56
56
|
Finally, use this preloaded data in your tests:
|
@@ -80,19 +80,19 @@ at the start of each test run. If you want finer grain control over which prelo
|
|
80
80
|
# test/user_test.rb
|
81
81
|
class UserTest < ActiveSupport::TestCase
|
82
82
|
preload_factory_data :users # multiple types can be listed as necessary
|
83
|
-
#
|
83
|
+
# tests go here...
|
84
84
|
end
|
85
85
|
|
86
86
|
# test/post_test.rb
|
87
87
|
class PostTest < ActiveSupport::TestCase
|
88
88
|
preload_factory_data :posts # dependencies are taken into account, so users will automatically be preloaded as well.
|
89
|
-
#
|
89
|
+
# tests go here...
|
90
90
|
end
|
91
91
|
|
92
92
|
== Notes, etc.
|
93
93
|
|
94
94
|
* This gem has been tested with Rails 2.2.2 and Rails 2.3.2.
|
95
|
-
* You can create the data using any
|
95
|
+
* You can create the data using any fixture replacement you want. In this contrived example, I just used ActiveRecord's
|
96
96
|
built in methods for simplicity's sake.
|
97
97
|
* FactoryData#preload does not actually preload the data. It simply defines the data that will be automatically preloaded
|
98
98
|
at the appropriate time (namely, at the same time when rails loads the fixtures).
|
@@ -106,6 +106,26 @@ at the start of each test run. If you want finer grain control over which prelo
|
|
106
106
|
* The preloader will also delete all records from the database, before any preloading begins. This is done at the same
|
107
107
|
time that rails deletes records for test fixtures. The tables are cleared using the reverse of the order defined by
|
108
108
|
your :depends_on options, so be sure to use :depends_on if you have foreign key constraints.
|
109
|
+
* Errors that occur during preloading are handled smartly: a warning is printed when one occurs, and an exception is raised
|
110
|
+
when the record that had the error is accessed. This should allow the rest of the data to be preloaded, and cause only
|
111
|
+
the tests that access the records with errors to fail.
|
112
|
+
* The syntax used before the 0.5.0 release is still allowed but has been deprecated. Instead of this:
|
113
|
+
|
114
|
+
FactoryData.preload(:users) do |data|
|
115
|
+
data[:thom] = User.create(:first_name => 'Thom', :last_name => 'York')
|
116
|
+
data[:john] = User.create(:first_name => 'John', :last_name => 'Doe') }
|
117
|
+
end
|
118
|
+
|
119
|
+
Use this:
|
120
|
+
|
121
|
+
FactoryData.preload(:users) do |data|
|
122
|
+
data.add(:thom) { User.create(:first_name => 'Thom', :last_name => 'York') }
|
123
|
+
data.add(:john) { User.create(:first_name => 'John', :last_name => 'Doe') }
|
124
|
+
end
|
125
|
+
|
126
|
+
== Known Issues
|
127
|
+
|
128
|
+
* This gem doesn't play nice with autotest.
|
109
129
|
|
110
130
|
== Copyright
|
111
131
|
|
data/VERSION.yml
CHANGED
@@ -14,6 +14,7 @@ require 'active_record/fixtures'
|
|
14
14
|
require 'factory_data_preloader/core_ext'
|
15
15
|
require 'factory_data_preloader/preloader'
|
16
16
|
require 'factory_data_preloader/preloader_collection'
|
17
|
+
require 'factory_data_preloader/preloaded_data_hash'
|
17
18
|
require 'factory_data_preloader/factory_data'
|
18
19
|
require 'factory_data_preloader/rails_core_ext'
|
19
20
|
|
@@ -4,12 +4,16 @@ module FactoryDataPreloader
|
|
4
4
|
class PreloaderAlreadyDefinedError < StandardError; end
|
5
5
|
class PreloadedRecordNotFound < StandardError; end
|
6
6
|
class DefinedPreloaderNotRunError < StandardError; end
|
7
|
+
class ErrorWhilePreloadingRecord < StandardError; end
|
8
|
+
|
9
|
+
module DataMethods
|
10
|
+
end
|
7
11
|
|
8
12
|
class FactoryData
|
9
|
-
@@preloaded_cache = nil
|
10
|
-
@@preloaded_data_deleted = nil
|
11
13
|
@@single_test_cache = {}
|
12
14
|
|
15
|
+
extend DataMethods
|
16
|
+
|
13
17
|
class << self
|
14
18
|
# An Array of strings specifying locations that should be searched for
|
15
19
|
# factory_data definitions. By default, factory_data_preloader will attempt to require
|
@@ -18,47 +22,29 @@ module FactoryDataPreloader
|
|
18
22
|
attr_accessor :definition_file_paths
|
19
23
|
|
20
24
|
def preload(model_type, options = {}, &proc)
|
21
|
-
|
25
|
+
if existing_preloader = AllPreloaders.instance.from_symbol(model_type, false)
|
26
|
+
existing_preloader.remove!
|
27
|
+
end
|
22
28
|
|
23
|
-
|
24
|
-
depends_on = [options[:depends_on]].compact.flatten
|
25
|
-
FactoryDataPreloader::Preloader.new(model_type, model_class, proc, depends_on)
|
29
|
+
FactoryDataPreloader::Preloader.new(model_type, options[:model_class], proc, options[:depends_on])
|
26
30
|
|
27
|
-
|
31
|
+
DataMethods.class_eval do
|
28
32
|
define_method model_type do |key|
|
29
|
-
get_record
|
33
|
+
FactoryData.send(:get_record, model_type, key)
|
30
34
|
end
|
31
35
|
end
|
32
36
|
end
|
33
37
|
|
34
38
|
def delete_preload_data!
|
35
|
-
# make sure this only runs once...
|
36
|
-
return unless @@preloaded_data_deleted.nil?
|
37
|
-
|
38
39
|
# Delete them in the reverse order of the dependencies, to handle foreign keys
|
39
|
-
FactoryDataPreloader.requested_preloaders.reverse.each do |preloader|
|
40
|
+
FactoryDataPreloader.requested_preloaders.dependency_order.reverse.each do |preloader|
|
40
41
|
preloader.model_class.delete_all
|
41
42
|
end
|
42
|
-
|
43
|
-
@@preloaded_data_deleted = true
|
44
43
|
end
|
45
44
|
|
46
45
|
def preload_data!
|
47
|
-
return unless @@preloaded_cache.nil? # make sure the data is only preloaded once.
|
48
|
-
@@preloaded_cache = {}
|
49
|
-
|
50
46
|
FactoryDataPreloader.requested_preloaders.dependency_order.each do |preloader|
|
51
|
-
|
52
|
-
preloader.data.each do |key, record|
|
53
|
-
if record.new_record? && !record.save
|
54
|
-
puts "\nError preloading factory data. #{preloader.model_class.to_s} :#{key.to_s} could not be saved. Errors: "
|
55
|
-
puts pretty_error_messages(record)
|
56
|
-
puts "\n\n"
|
57
|
-
next
|
58
|
-
end
|
59
|
-
|
60
|
-
cache[key] = record.id
|
61
|
-
end
|
47
|
+
preloader.preload!
|
62
48
|
end
|
63
49
|
end
|
64
50
|
|
@@ -80,25 +66,10 @@ module FactoryDataPreloader
|
|
80
66
|
|
81
67
|
private
|
82
68
|
|
83
|
-
def get_record(type,
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
@@single_test_cache[type] ||= {}
|
89
|
-
@@single_test_cache[type][key] ||= begin
|
90
|
-
record = model_class.find_by_id(@@preloaded_cache[type][key])
|
91
|
-
raise PreloadedRecordNotFound.new, "Could not find a record for FactoryData.#{type}(:#{key})." unless record
|
92
|
-
record
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# Borrowed from shoulda: http://github.com/thoughtbot/shoulda/blob/e02228d45a879ff92cb72b84f5fccc6a5f856a65/lib/shoulda/active_record/helpers.rb#L4-9
|
97
|
-
def pretty_error_messages(obj)
|
98
|
-
obj.errors.map do |a, m|
|
99
|
-
msg = "#{a} #{m}"
|
100
|
-
msg << " (#{obj.send(a).inspect})" unless a.to_sym == :base
|
101
|
-
end
|
69
|
+
def get_record(type, key)
|
70
|
+
preloader = AllPreloaders.instance.from_symbol(type)
|
71
|
+
@@single_test_cache[type] ||= {}
|
72
|
+
@@single_test_cache[type][key] ||= preloader.get_record(key)
|
102
73
|
end
|
103
74
|
end
|
104
75
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class PreloadedDataHash
|
2
|
+
attr_reader :preloader
|
3
|
+
|
4
|
+
def initialize(preloader)
|
5
|
+
@preloader, @backing_hash = preloader, {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def []=(key, record)
|
9
|
+
puts "DEPRECATION WARNING: Instead of 'data[:#{key}] = record' please use 'data.add(:#{key}) { record }'"
|
10
|
+
add_to_backing_hash(key, record)
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](key)
|
14
|
+
@backing_hash[key]
|
15
|
+
end
|
16
|
+
|
17
|
+
def record_ids
|
18
|
+
@backing_hash.values.select { |value| value.is_a?(Fixnum) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(key)
|
22
|
+
raise "You must pass a block to PreloaderDataHash#add. You forgot to use the block in your #{preloader.model_type} prelodaer for the #{key.inspect} record." unless block_given?
|
23
|
+
begin
|
24
|
+
add_to_backing_hash(key, yield)
|
25
|
+
rescue => e
|
26
|
+
puts "WARNING: an error occurred while preloading the #{preloader.model_type.to_s}(:#{key}) record: #{e.class.to_s}: #{e.message}"
|
27
|
+
add_to_backing_hash(key, nil, e)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def add_to_backing_hash(key, record, error = nil)
|
34
|
+
print '.'
|
35
|
+
if record
|
36
|
+
if record.new_record? && !record.save
|
37
|
+
raise StandardError.new("Error preloading factory data. #{preloader.model_class.to_s} :#{key.to_s} could not be saved. Errors: #{pretty_error_messages(record)}")
|
38
|
+
else
|
39
|
+
@backing_hash[key] = record.id
|
40
|
+
end
|
41
|
+
else
|
42
|
+
@backing_hash[key] = error
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Borrowed from shoulda: http://github.com/thoughtbot/shoulda/blob/e02228d45a879ff92cb72b84f5fccc6a5f856a65/lib/shoulda/active_record/helpers.rb#L4-9
|
47
|
+
def pretty_error_messages(obj)
|
48
|
+
obj.errors.map do |a, m|
|
49
|
+
msg = "#{a} #{m}"
|
50
|
+
msg << " (#{obj.send(a).inspect})" unless a.to_sym == :base
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/deprecation'
|
2
|
+
|
1
3
|
module FactoryDataPreloader
|
2
4
|
class PreloaderNotDefinedError < StandardError; end
|
3
5
|
|
@@ -11,50 +13,81 @@ module FactoryDataPreloader
|
|
11
13
|
alias :preload_all? :preload_all
|
12
14
|
|
13
15
|
def requested_preloaders
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
PreloaderCollection.new(preloaders)
|
22
|
-
end
|
16
|
+
if preload_all?
|
17
|
+
AllPreloaders.instance
|
18
|
+
else
|
19
|
+
preloaders = self.preload_types.collect { |type| AllPreloaders.instance.from_symbol(type) }
|
20
|
+
preloaders += (preloaders.collect { |p| p.all_dependencies }).flatten
|
21
|
+
preloaders.uniq!
|
22
|
+
PreloaderCollection.new(preloaders)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
27
|
class Preloader
|
28
28
|
attr_accessor :model_type, :model_class, :proc, :depends_on
|
29
|
+
attr_reader :data
|
29
30
|
|
30
31
|
def initialize(model_type, model_class, proc, depends_on)
|
31
|
-
|
32
|
+
model_class ||= model_type.to_s.pluralize.classify.constantize
|
33
|
+
|
34
|
+
@model_type, @model_class, @proc, @depends_on = model_type, model_class, proc, [depends_on].compact.flatten
|
32
35
|
AllPreloaders.instance << self
|
33
|
-
end
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
benchmark_measurement = Benchmark.measure { self.proc.try(:call, data) }
|
40
|
-
print "(#{format('%.3f', benchmark_measurement.real)} secs)\n"
|
41
|
-
data
|
37
|
+
DataMethods.class_eval do
|
38
|
+
define_method model_type do |key|
|
39
|
+
FactoryData.send(:get_record, model_type, key)
|
40
|
+
end
|
42
41
|
end
|
43
42
|
end
|
44
43
|
|
44
|
+
def preload!
|
45
|
+
@data = PreloadedDataHash.new(self)
|
46
|
+
print "Preloading #{model_type}:"
|
47
|
+
benchmark_measurement = Benchmark.measure { self.proc.try(:call, @data) }
|
48
|
+
print "(#{format('%.3f', benchmark_measurement.real)} secs)\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
def preloaded?
|
52
|
+
!@data.nil?
|
53
|
+
end
|
54
|
+
|
45
55
|
def dependencies
|
46
|
-
|
56
|
+
self.depends_on.collect { |dependency| AllPreloaders.instance.from_symbol(dependency) }
|
47
57
|
end
|
48
58
|
|
49
59
|
def all_dependencies
|
50
|
-
|
60
|
+
(self.dependencies + (self.dependencies.collect { |d| d.all_dependencies }).flatten).uniq
|
51
61
|
end
|
52
|
-
end
|
53
62
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
63
|
+
def get_record(key)
|
64
|
+
unless self.preloaded?
|
65
|
+
raise DefinedPreloaderNotRunError.new, "The :#{self.model_type} preloader has never been run. Did you forget to add the 'preload_factory_data :#{self.model_type}' declaration to your test case? You'll need this at the top of your test case class if you want to use the factory data defined by this preloader."
|
66
|
+
end
|
67
|
+
|
68
|
+
unless record_id_or_error = self.data[key]
|
69
|
+
raise PreloadedRecordNotFound.new, "Could not find a preloaded record #{self.model_type} recore for :#{key}. Did you mispell :#{key}?"
|
70
|
+
end
|
71
|
+
|
72
|
+
if record_id_or_error.is_a?(Exception)
|
73
|
+
raise ErrorWhilePreloadingRecord.new, "An error occurred while preloading #{self.model_type}(:#{key}): #{record_id_or_error.class.to_s}: #{record_id_or_error.message}\n\nBacktrace:\n\n#{record_id_or_error.backtrace}"
|
74
|
+
end
|
75
|
+
|
76
|
+
self.model_class.find_by_id(record_id_or_error)
|
77
|
+
end
|
78
|
+
|
79
|
+
def remove!
|
80
|
+
preloader = self
|
81
|
+
DataMethods.class_eval do
|
82
|
+
remove_method(preloader.model_type) if method_defined?(preloader.model_type)
|
83
|
+
end
|
84
|
+
|
85
|
+
if @data
|
86
|
+
self.model_class.delete_all(:id => @data.record_ids)
|
87
|
+
@data = nil
|
88
|
+
end
|
89
|
+
|
90
|
+
AllPreloaders.instance.delete(self)
|
58
91
|
end
|
59
92
|
end
|
60
93
|
|
@@ -15,9 +15,9 @@ module FactoryDataPreloader
|
|
15
15
|
ordered_preloaders
|
16
16
|
end
|
17
17
|
|
18
|
-
def from_symbol(symbol)
|
18
|
+
def from_symbol(symbol, raise_error = true)
|
19
19
|
unless preloader = self.detect { |p| p.model_type == symbol }
|
20
|
-
raise PreloaderNotDefinedError, "The preloader for :#{symbol} has not been defined."
|
20
|
+
raise PreloaderNotDefinedError, "The preloader for :#{symbol} has not been defined." if raise_error
|
21
21
|
end
|
22
22
|
preloader
|
23
23
|
end
|
data/test/factory_data_test.rb
CHANGED
@@ -8,42 +8,52 @@ class FactoryDataTest < Test::Unit::TestCase
|
|
8
8
|
context 'Calling FactoryData.preload(:users)' do
|
9
9
|
setup do
|
10
10
|
FactoryData.preload(:users) do |data|
|
11
|
-
data
|
11
|
+
data.add(:thom) { User.create(:first_name => 'Thom', :last_name => 'York') }
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
should_not_change 'User.count'
|
16
16
|
should_change "FactoryData.methods.include?('users')", :from => false, :to => true
|
17
17
|
|
18
|
-
should 'not allow it to be called again' do
|
19
|
-
assert_raise FactoryDataPreloader::PreloaderAlreadyDefinedError do
|
20
|
-
FactoryData.preload(:users)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
18
|
context 'when there was a previous user record in the database' do
|
25
19
|
setup { User.create(:first_name => 'Barack', :last_name => 'Obama') }
|
26
20
|
|
27
21
|
context 'and calling FactoryData.delete_preload_data!' do
|
28
22
|
setup { FactoryData.delete_preload_data! }
|
29
23
|
should_change 'User.count', :to => 0
|
30
|
-
|
31
|
-
context 'and there is another record in the database' do
|
32
|
-
setup { User.create(:first_name => 'George', :last_name => 'Bush') }
|
33
|
-
|
34
|
-
context 'and FactoryData.delete_preload_data! is called again' do
|
35
|
-
setup { FactoryData.delete_preload_data! }
|
36
|
-
should_not_change 'User.count'
|
37
|
-
end
|
38
|
-
end
|
39
24
|
end
|
40
25
|
end
|
41
26
|
|
42
27
|
context 'and later calling FactoryData.preload_data!' do
|
43
|
-
setup
|
28
|
+
setup do
|
29
|
+
@out, @err = OutputCapturer.capture do
|
30
|
+
FactoryData.preload_data!
|
31
|
+
end
|
32
|
+
end
|
44
33
|
|
45
34
|
should_change 'User.count', :by => 1
|
46
35
|
|
36
|
+
context 'and later re-defining the preloaders' do
|
37
|
+
setup do
|
38
|
+
FactoryData.preload(:users) do |data|
|
39
|
+
data.add(:thom) { User.create(:first_name => 'Thom', :last_name => 'York') }
|
40
|
+
data.add(:john) { User.create(:first_name => 'John', :last_name => 'Doe') }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
should_change 'User.count', :by => -1
|
45
|
+
|
46
|
+
context 'and preloading the re-defined preloader' do
|
47
|
+
setup do
|
48
|
+
@out, @err = OutputCapturer.capture do
|
49
|
+
FactoryData.preload_data!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
should_change 'User.count', :by => 2
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
47
57
|
context 'and later calling FactoryData.users(key)' do
|
48
58
|
setup { @user = FactoryData.users(:thom) }
|
49
59
|
|
@@ -77,47 +87,14 @@ class FactoryDataTest < Test::Unit::TestCase
|
|
77
87
|
end
|
78
88
|
end
|
79
89
|
|
80
|
-
context 'Preloading a record that has not been saved' do
|
81
|
-
setup do
|
82
|
-
@unsaved_user = User.new(:first_name => 'George', :last_name => 'Washington')
|
83
|
-
assert @unsaved_user.new_record?
|
84
|
-
|
85
|
-
FactoryData.preload(:users) do |data|
|
86
|
-
data[:george] = @unsaved_user
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
should 'save the record wen preload_data! is called' do
|
91
|
-
FactoryData.preload_data!
|
92
|
-
assert !@unsaved_user.new_record?
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
context 'Preloading a record that cannot be saved to the database' do
|
97
|
-
setup do
|
98
|
-
@invalid_user = User.new(:first_name => 'Bob')
|
99
|
-
assert !@invalid_user.valid?
|
100
|
-
|
101
|
-
FactoryData.preload(:users) do |data|
|
102
|
-
data[:bob] = @invalid_user
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
should 'print an appropriate error message when preload_data! is called' do
|
107
|
-
out, err = OutputCapturer.capture do
|
108
|
-
FactoryData.preload_data!
|
109
|
-
end
|
110
|
-
|
111
|
-
assert_match /Error preloading factory data\.\s+User :bob could not be saved\.\s+Errors:\s+last_name can't be blank/im, out
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
90
|
context 'Preloading with an explicit :model_class option' do
|
116
91
|
setup do
|
117
92
|
FactoryData.preload(:posts, :model_class => User) do |data|
|
118
|
-
data
|
93
|
+
data.add(:george) { User.create(:first_name => 'George', :last_name => 'Washington') }
|
94
|
+
end
|
95
|
+
@out, @err = OutputCapturer.capture do
|
96
|
+
FactoryData.preload_data!
|
119
97
|
end
|
120
|
-
FactoryData.preload_data!
|
121
98
|
end
|
122
99
|
|
123
100
|
should 'use the passed model_class rather than inferring the class from the symbol' do
|
@@ -128,23 +105,26 @@ class FactoryDataTest < Test::Unit::TestCase
|
|
128
105
|
context 'Preloading multiple record types, with dependencies' do
|
129
106
|
setup do
|
130
107
|
FactoryData.preload(:comments, :depends_on => [:users, :posts]) do |data|
|
131
|
-
data
|
108
|
+
data.add(:woohoo) { FactoryData.users(:john).comments.create(:post => FactoryData.posts(:tour), :comment => "I can't wait!") }
|
132
109
|
end
|
133
110
|
|
134
111
|
FactoryData.preload(:posts, :depends_on => :users) do |data|
|
135
|
-
data
|
112
|
+
data.add(:tour) { FactoryData.users(:thom).posts.create(:title => 'Tour!', :body => 'Radiohead will tour soon.') }
|
136
113
|
end
|
137
114
|
|
138
115
|
FactoryData.preload(:users) do |data|
|
139
|
-
data
|
140
|
-
data
|
116
|
+
data.add(:thom) { User.create(:first_name => 'Thom', :last_name => 'York') }
|
117
|
+
data.add(:john) { User.create(:first_name => 'John', :last_name => 'Doe') }
|
141
118
|
end
|
142
119
|
end
|
143
120
|
|
144
121
|
should "raise the appropriate error when a developer tries to access a record that wasn't preloaded" do
|
145
122
|
FactoryDataPreloader.preload_all = false
|
146
123
|
FactoryDataPreloader.preload_types << :users
|
147
|
-
|
124
|
+
|
125
|
+
@out, @err = OutputCapturer.capture do
|
126
|
+
FactoryData.preload_data!
|
127
|
+
end
|
148
128
|
|
149
129
|
assert FactoryData.users(:thom)
|
150
130
|
assert_raise FactoryDataPreloader::DefinedPreloaderNotRunError do
|
@@ -153,7 +133,10 @@ class FactoryDataTest < Test::Unit::TestCase
|
|
153
133
|
end
|
154
134
|
|
155
135
|
should 'preload them in the proper order, allowing you to use the dependencies' do
|
156
|
-
|
136
|
+
@out, @err = OutputCapturer.capture do
|
137
|
+
FactoryData.preload_data!
|
138
|
+
end
|
139
|
+
|
157
140
|
assert_equal 'Thom', FactoryData.users(:thom).first_name
|
158
141
|
assert_equal 'John', FactoryData.users(:john).first_name
|
159
142
|
|
data/test/lib/models.rb
CHANGED
data/test/lib/schema.rb
CHANGED
@@ -0,0 +1,88 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class PreloadedDataHashTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
FactoryDataPreloader.reset!
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.test_add_valid_record(desc, &block)
|
9
|
+
context desc do
|
10
|
+
setup do
|
11
|
+
@out, @err = OutputCapturer.capture do
|
12
|
+
@preloaded_data_hash.add(:record) { @user = instance_eval(&block) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
should 'print a dot' do
|
17
|
+
assert_equal '', @err
|
18
|
+
assert_equal '.', @out
|
19
|
+
end
|
20
|
+
|
21
|
+
should 'add the record id to the hash' do
|
22
|
+
assert_equal @user.id, @preloaded_data_hash[:record]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.test_add_invalid_record(desc, error_msg_regex, &block)
|
28
|
+
context desc do
|
29
|
+
setup do
|
30
|
+
@out, @err = OutputCapturer.capture do
|
31
|
+
@preloaded_data_hash.add(:record) { instance_eval(&block) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
should 'print a warning message' do
|
36
|
+
assert_equal '', @err
|
37
|
+
assert_match /WARNING: an error occurred while preloading/, @out
|
38
|
+
end
|
39
|
+
|
40
|
+
should 'add an error message to the hash' do
|
41
|
+
assert @preloaded_data_hash[:record].is_a?(Exception)
|
42
|
+
assert_match error_msg_regex, @preloaded_data_hash[:record].message
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'For a new preloader data hash' do
|
48
|
+
setup do
|
49
|
+
@preloaded_data_hash = PreloadedDataHash.new(stub_everything(:model_class => User))
|
50
|
+
end
|
51
|
+
|
52
|
+
test_add_valid_record('when a saved record is added') { User.create!(:first_name => 'Barack', :last_name => 'Obama') }
|
53
|
+
test_add_valid_record('when a valid unsaved record is added') { User.new(:first_name => 'Barack', :last_name => 'Obama') }
|
54
|
+
test_add_invalid_record('when an invalid unsaved record is added', /Error preloading factory data.*could not be saved/) { User.new }
|
55
|
+
test_add_invalid_record('when an error occurs while adding the preloading a record', /This is an error/) { raise 'This is an error' }
|
56
|
+
|
57
|
+
context 'adding a record through the deprecated []= method' do
|
58
|
+
setup do
|
59
|
+
@out, @err = OutputCapturer.capture do
|
60
|
+
@preloaded_data_hash[:record] = (@user = User.create!(:first_name => 'Barack', :last_name => 'Obama'))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
should 'print a deprecation warning' do
|
65
|
+
assert_equal '', @err
|
66
|
+
assert_match /DEPRECATION WARNING: Instead of .* please use .*/, @out
|
67
|
+
end
|
68
|
+
|
69
|
+
should 'add the record id to the hash' do
|
70
|
+
assert_equal @user.id, @preloaded_data_hash[:record]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when multiple records and errors have been added' do
|
75
|
+
setup do
|
76
|
+
@out, @err = OutputCapturer.capture do
|
77
|
+
@preloaded_data_hash.add(:barack) { @barack = User.create!(:first_name => 'Barack', :last_name => 'Obama') }
|
78
|
+
@preloaded_data_hash.add(:error) { raise 'An error' }
|
79
|
+
@preloaded_data_hash.add(:george) { @george = User.create!(:first_name => 'George', :last_name => 'Washington') }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
should 'return the record ids for #record_ids' do
|
84
|
+
assert_same_elements [@barack.id, @george.id], @preloaded_data_hash.record_ids
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/test/preloader_test.rb
CHANGED
@@ -8,21 +8,66 @@ class PreloaderTest < Test::Unit::TestCase
|
|
8
8
|
context 'A new preloader' do
|
9
9
|
setup do
|
10
10
|
proc = lambda { |data|
|
11
|
-
data
|
12
|
-
data
|
11
|
+
data.add(:thom) { User.create(:first_name => 'Thom', :last_name => 'York') }
|
12
|
+
data.add(:john) { User.create(:first_name => 'John', :last_name => 'Doe') }
|
13
13
|
}
|
14
14
|
@preloader = FactoryDataPreloader::Preloader.new(:users, User, proc, [])
|
15
15
|
end
|
16
16
|
|
17
|
-
should 'return the preloaded data for #data' do
|
18
|
-
data = @preloader.data
|
19
|
-
assert_equal 'York', data[:thom].last_name
|
20
|
-
assert_equal 'Doe', data[:john].last_name
|
21
|
-
end
|
22
|
-
|
23
17
|
should 'be automatically added to the PreloaderCollection' do
|
24
18
|
assert_equal [@preloader], FactoryDataPreloader::AllPreloaders.instance
|
25
19
|
end
|
20
|
+
|
21
|
+
context 'when preloaded' do
|
22
|
+
setup do
|
23
|
+
@out, @err = OutputCapturer.capture do
|
24
|
+
@preloader.preload!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'return the preloaded data when #get_record is called' do
|
29
|
+
assert_equal 'York', @preloader.get_record(:thom).last_name
|
30
|
+
assert_equal 'Doe', @preloader.get_record(:john).last_name
|
31
|
+
end
|
32
|
+
|
33
|
+
should 'print out a preloader message, a dot for each record and a benchmark' do
|
34
|
+
assert_equal '', @err
|
35
|
+
assert_match /Preloading users:\.\.\([\d\.]+ secs\)/, @out
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'A new preloader for email_addresses' do
|
41
|
+
setup do
|
42
|
+
@preloader = FactoryDataPreloader::Preloader.new(:email_addresses, nil, lambda { }, [])
|
43
|
+
end
|
44
|
+
|
45
|
+
should 'infer the model class' do
|
46
|
+
assert_equal EmailAddress, @preloader.model_class
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'A preloader with errors' do
|
51
|
+
setup do
|
52
|
+
proc = lambda { |data|
|
53
|
+
data.add(:thom) { raise StandardError('Error for thom') }
|
54
|
+
data.add(:john) { @john = User.create(:first_name => 'John', :last_name => 'Doe') }
|
55
|
+
}
|
56
|
+
@preloader = FactoryDataPreloader::Preloader.new(:users, User, proc, [])
|
57
|
+
@out, @err = OutputCapturer.capture do
|
58
|
+
@preloader.preload!
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
should 'raise an exception when the record with the error is accessed' do
|
63
|
+
assert_raise FactoryDataPreloader::ErrorWhilePreloadingRecord do
|
64
|
+
@preloader.get_record(:thom)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
should 'allow the error-free records to be accessed, even when they were created after the error record' do
|
69
|
+
assert_equal @john, @preloader.get_record(:john)
|
70
|
+
end
|
26
71
|
end
|
27
72
|
|
28
73
|
context 'A preloader with dependencies' do
|
data/test/test_helper.rb
CHANGED
@@ -42,28 +42,13 @@ module FactoryDataPreloader
|
|
42
42
|
def self.reset!
|
43
43
|
self.preload_all = true
|
44
44
|
self.preload_types = []
|
45
|
-
@requested_preloaders = nil
|
46
|
-
FactoryData.reset!
|
47
|
-
end
|
48
|
-
|
49
|
-
class FactoryData
|
50
|
-
# helper method to reset the factory data between test runs.
|
51
|
-
def self.reset!
|
52
|
-
FactoryDataPreloader::AllPreloaders.instance.each do |preloader|
|
53
|
-
class << self; self; end.class_eval do
|
54
|
-
remove_method(preloader.model_type) if method_defined?(preloader.model_type)
|
55
|
-
end
|
56
45
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
@@preloaded_cache = nil
|
63
|
-
@@preloaded_data_deleted = nil
|
64
|
-
@@single_test_cache = {}
|
65
|
-
FactoryDataPreloader::AllPreloaders.instance.clear
|
46
|
+
preloaders = Array.new(FactoryDataPreloader::AllPreloaders.instance)
|
47
|
+
preloaders.each do |preloader|
|
48
|
+
preloader.remove!
|
66
49
|
end
|
50
|
+
|
51
|
+
FactoryData.reset_cache!
|
67
52
|
end
|
68
53
|
end
|
69
54
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: myronmarston-factory_data_preloader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Myron Marston
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-07-07 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -42,11 +42,13 @@ extra_rdoc_files:
|
|
42
42
|
- README.rdoc
|
43
43
|
- LICENSE
|
44
44
|
files:
|
45
|
+
- CHANGELOG.rdoc
|
45
46
|
- README.rdoc
|
46
47
|
- VERSION.yml
|
47
48
|
- lib/factory_data_preloader
|
48
49
|
- lib/factory_data_preloader/core_ext.rb
|
49
50
|
- lib/factory_data_preloader/factory_data.rb
|
51
|
+
- lib/factory_data_preloader/preloaded_data_hash.rb
|
50
52
|
- lib/factory_data_preloader/preloader.rb
|
51
53
|
- lib/factory_data_preloader/preloader_collection.rb
|
52
54
|
- lib/factory_data_preloader/rails_core_ext.rb
|
@@ -55,6 +57,7 @@ files:
|
|
55
57
|
- test/lib
|
56
58
|
- test/lib/models.rb
|
57
59
|
- test/lib/schema.rb
|
60
|
+
- test/preloaded_data_hash_test.rb
|
58
61
|
- test/preloader_test.rb
|
59
62
|
- test/test_helper.rb
|
60
63
|
- LICENSE
|