iron_fixture_extractor 0.1.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +8 -0
- data/Gemfile +5 -1
- data/README.md +48 -79
- data/iron_fixture_extractor.gemspec +1 -0
- data/lib/fe.rb +123 -1
- data/lib/fe/extractor.rb +109 -20
- data/lib/fe/factory_girl_dsl_methods.rb +28 -0
- data/lib/fe/railtie.rb +7 -0
- data/lib/fe/tasks/iron_fixture_extractor.rake +12 -0
- data/lib/fe/version.rb +1 -1
- data/test/basic_usage_test.rb +38 -18
- data/test/different_target_table_test.rb +35 -0
- data/test/factory_girl_test.rb +77 -0
- data/test/fe_test_env.rb +1 -1
- data/test/get_hash_test.rb +35 -0
- data/test/migrations/20120604043601_create_posts.rb +1 -0
- data/test/migrations/20120604043603_create_different_posts.rb +14 -0
- data/test/migrations/20120604043819_create_users.rb +10 -0
- data/test/models/complex_thing.rb +4 -0
- data/test/models/different_post.rb +6 -0
- data/test/models/group.rb +1 -1
- data/test/models/post.rb +2 -1
- data/test/models/serialized_attribute_encoder.rb +12 -0
- data/test/models/user.rb +2 -0
- data/test/models/user/admin.rb +2 -0
- data/test/models/user/jerk.rb +2 -0
- data/test/multi_tree_usage_test.rb +25 -0
- data/test/serialized_attribute_test.rb +27 -0
- data/test/sti_test.rb +20 -0
- data/test/test_data_migrations/001_create_some_data.rb +10 -7
- data/test/test_helper.rb +2 -1
- metadata +46 -3
data/CHANGELOG.md
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
## 0.1.1 -> 1.0.0
|
2
|
+
* Fe.extract must be given a string or array of ActiveRecord queries
|
3
|
+
like this
|
4
|
+
|
5
|
+
* Fe.get_hash, truncate_tables_for, execute_extract_code,
|
6
|
+
to_factory_girl_string, make their debut...only get_hash is truly
|
7
|
+
awesome...the others...not so much
|
8
|
+
|
data/Gemfile
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
+
|
2
3
|
# TEMP CRAP FOR DEV, COMMENT OUT OR DELETE
|
4
|
+
#
|
5
|
+
gem 'debugger'
|
6
|
+
|
3
7
|
# USED w ruby 1.9.2
|
4
8
|
# http://dirk.net/2010/04/17/ruby-debug-with-ruby-19x-and-rails-3-on-rvm/
|
5
|
-
gem 'ruby-debug19', :require => 'ruby-debug'
|
9
|
+
#gem 'ruby-debug19', :require => 'ruby-debug'
|
6
10
|
gem 'rake'
|
7
11
|
# Specify your gem's dependencies in iron_fixture_extractor.gemspec
|
8
12
|
gemspec
|
data/README.md
CHANGED
@@ -1,110 +1,77 @@
|
|
1
|
-
# About
|
2
|
-
|
3
|
-
When object factories don't work because your data is too complex and creating manual fixtures is cumbersome and brittle: Iron Fixture Extractor.
|
4
|
-
|
5
|
-
Iron fixture extractor makes extracting complex ActiveRecord dependency graphs from live databases sane. Feed it an array of ActiveRecord objects that have preloaded associations via the .include method or just an adhoc array of ActiveRecord instances you want to capture as fixtures and it will write a bunch of fixture files for usage in your test cases.
|
6
|
-
|
7
|
-
`###
|
8
|
-
,#
|
9
|
-
+#,
|
10
|
-
;+############++++++++++++++++++++++++++++
|
11
|
-
; + `:
|
12
|
-
## +# ++,
|
13
|
-
.++` ;#; :+
|
14
|
-
'' ;+` `;;'
|
15
|
-
;::' `;;. +;;+'
|
16
|
-
:;:;': +;;'' '+'+++:
|
17
|
-
`:';'++. '+''+`; .;;;;;''.
|
18
|
-
:,'''';; `````````
|
19
|
-
|
20
|
-
~|~ _ _ _ |~. _|_ _ _ (~ _|_ _ _ __|_ _ _
|
21
|
-
_|_| (_)| | |~|><||_|| (/_ (_><| | (_|(_ | (_)|
|
22
|
-
|
23
|
-
Iron Fixture Extractor
|
24
|
-
is
|
25
|
-
handy when
|
26
|
-
you require complex data extracted from
|
27
|
-
crusty legacy
|
28
|
-
or
|
29
|
-
big ERP
|
30
|
-
databases
|
31
|
-
for
|
32
|
-
test cases.
|
33
|
-
|
34
|
-
## Installation
|
35
|
-
Add this line to your application's Gemfile:
|
1
|
+
# About Iron Fixture Extractor
|
36
2
|
|
37
|
-
|
3
|
+
For extracting complex data from staging and production databases to be used for automated testing (works great with whatever testing framework your using).
|
38
4
|
|
39
|
-
|
5
|
+
Its best when:
|
6
|
+
* your data is too complex for factories (like when integrating with legacy systems, ERP systems, etc)
|
7
|
+
* creating and maintaining manual fixtures is cumbersome and brittle (always, :))
|
40
8
|
|
41
|
-
|
9
|
+
Its good for:
|
42
10
|
|
43
|
-
|
11
|
+
Pulling data from a staging database containing vetted data that has
|
12
|
+
been built up by the development team, users, or business analysts to be used
|
13
|
+
as "archetypical" data structures in test cases, demonstration.
|
44
14
|
|
45
|
-
|
46
|
-
|
47
|
-
## Usage
|
48
|
-
The Iron Fixture Extractor gem exposes everything under the Fe
|
49
|
-
namespace, we'll refer to it as "Fe" from here on out.
|
15
|
+
Taking snapshots of production data that has triggered unexpected errors to be incorporated into test cases for closer inspection and correction.
|
50
16
|
|
51
|
-
|
52
|
-
The idea is to poke around your data via your ActiveRecord models, then
|
53
|
-
once you have a good dataset, use Fe.extract to load it into fixture
|
54
|
-
files you can write tests against.
|
17
|
+
How it works:
|
55
18
|
|
56
|
-
|
57
|
-
and test cases directly to clarify any behavioral details this readme
|
58
|
-
doesn't cover.
|
19
|
+
Feed it an array of ActiveRecord objects or ActiveRelation object and it will allow you to extract, load, and rebuild the records associated with your queries.
|
59
20
|
|
60
|
-
|
21
|
+
## Usage (typically in a console)
|
22
|
+
### Extract (fixture files)
|
61
23
|
|
62
|
-
Fe.extract 'Post.includes(:comments, :author).limit(1)', name => 'first_post_w_comments_and_authors'
|
24
|
+
Fe.extract 'Post.includes(:comments, :author).limit(1)', :name => 'first_post_w_comments_and_authors'
|
63
25
|
|
64
|
-
### Load
|
26
|
+
### Load (dataset into database)
|
65
27
|
|
66
28
|
Fe.load_db(:first_post_w_comments_and_authors)
|
67
29
|
|
68
|
-
### Rebuild
|
69
|
-
This uses the fe_manifest.yml's extract_code to re-extract fixtures
|
70
|
-
using the same code used to initially create them. Its handy when the live data changes and you want to refresh the fixture files to reflect it.
|
30
|
+
### Rebuild (fixture files associated with the initial extraction)
|
71
31
|
|
72
32
|
Fe.rebuild(:first_post_w_comments_and_authors)
|
73
33
|
|
74
|
-
|
34
|
+
### Pull up a hash from a particular fixture file (very handy in test cases)
|
35
|
+
Fe.get_hash(:first_post_w_comments_and_authors, Post, 'r1')
|
36
|
+
or
|
37
|
+
Fe.get_hash(:first_post_w_comments_and_authors, Post, :first)
|
38
|
+
or
|
39
|
+
Fe.get_hash(:first_post_w_comments_and_authors, Post, :last)
|
75
40
|
|
76
|
-
|
77
|
-
|
41
|
+
## Installation
|
42
|
+
Add this line to your application's Gemfile:
|
78
43
|
|
79
|
-
|
80
|
-
recursively resolve any association pre-loaded in the .association_cache [ActiveRecord] method
|
81
|
-
add it to a set of records keyed by model name
|
82
|
-
write each set of records as a <model_name>.yml fixture file to test/fe_fixtures/<the :name specified to .extract>/
|
44
|
+
gem 'iron_fixture_extractor'
|
83
45
|
|
84
|
-
|
46
|
+
And then execute:
|
85
47
|
|
86
|
-
|
87
|
-
p.comments
|
88
|
-
Fe.extract(p)
|
48
|
+
$ bundle
|
89
49
|
|
90
|
-
|
50
|
+
Or install it yourself as:
|
91
51
|
|
92
|
-
|
93
|
-
|
52
|
+
$ gem install iron_fixture_extractor
|
53
|
+
|
54
|
+
### Extract
|
55
|
+
The essense of the Fe.extract is dirt simple:
|
56
|
+
|
57
|
+
for each record given to Fe.extract
|
58
|
+
recursively resolve any association pre-loaded in the .association_cache [ActiveRecord] method
|
59
|
+
add it to a set of records keyed by model name
|
60
|
+
write each set of records as a <TheModel.table_name>.yml fixture
|
61
|
+
write a fe_manifest.yml that will allow you to later change the query, inspect row counts, and rebuild the fixtures by re-executing the originate queries
|
94
62
|
|
95
|
-
### Rebuild Fixture Files
|
96
|
-
This is just like .extract, except the code used to do the query is
|
97
|
-
pulled from the fe_manifest.yml file.
|
98
63
|
|
99
64
|
## Missing Features
|
100
|
-
* rake fe:fixtures:extract, fe:fixtures:load_db, and fe:fixtures:rebuild
|
101
|
-
ought exist and be available in Rails context via a Railtie. They would simply wrap the capabilities of Fe's extract, load_db, and rebuild method.
|
102
65
|
* If you give a non-string arg to .extract, the manifest should resolve
|
103
66
|
the .extract_code to be a bunch of look-ups by primary key ala [Post.find(1),Comment.find(2)].
|
104
67
|
* The output of each of the main commands should be meaningful, aka,
|
105
68
|
make extractor implement a sensible .to_s and .inspect
|
106
69
|
* load_db should error if Rails.env or RAILS_ENV is defined and set to
|
107
70
|
production
|
71
|
+
* An :extract_schema option passed to .extract that uses `rake db:structure:dump` functionality
|
72
|
+
or ActiveRecord::Base.connection.structure_dump to create .sql files containing a "create table" statement
|
73
|
+
for each distinct model class. This would allow you to completely de-couple your test cases + fixtures
|
74
|
+
from the external databases they were extracted from.
|
108
75
|
|
109
76
|
## Contributing
|
110
77
|
To run test cases:
|
@@ -118,9 +85,11 @@ usual github approach:
|
|
118
85
|
|
119
86
|
1. Fork it
|
120
87
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
121
|
-
3.
|
122
|
-
4.
|
123
|
-
5.
|
88
|
+
3. Ensure the test cases run
|
89
|
+
4. Copy one of the test cases (like basic_test.rb), rename, rip out the guts, and add some tests + code to the app
|
90
|
+
5. Commit your changes (`git commit -am 'Added some feature'`)
|
91
|
+
6. Push to the branch (`git push origin my-new-feature`)
|
92
|
+
7. Create new Pull Request
|
124
93
|
|
125
94
|
If you have other ideas for this tool, make a Github Issue.
|
126
95
|
|
data/lib/fe.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# NOTE: require 'iron_fixture_extractor', NOT this file
|
2
2
|
module Fe
|
3
|
+
class InvalidSourceModelToMapFrom < Exception; end
|
3
4
|
extend ActiveSupport::Autoload
|
4
5
|
autoload :Extractor
|
6
|
+
autoload :FactoryGirlDslMethods
|
7
|
+
require 'fe/railtie' if defined?(Rails)
|
5
8
|
|
6
9
|
# global configuration
|
7
10
|
|
@@ -10,6 +13,12 @@ module Fe
|
|
10
13
|
|
11
14
|
# Top-level API methods
|
12
15
|
class << self
|
16
|
+
# Extract a set up Yml for one or more active relation alls
|
17
|
+
# You can call this in two ways
|
18
|
+
# Fe.extract('Post.all', :name => :bla)
|
19
|
+
# or
|
20
|
+
# Fe.extract('[Post.all,Comment.all]', :name => :bla2)
|
21
|
+
#
|
13
22
|
def extract(*args)
|
14
23
|
extractor = Fe::Extractor.new
|
15
24
|
extractor.load_from_args(*args)
|
@@ -17,15 +26,27 @@ module Fe
|
|
17
26
|
extractor
|
18
27
|
end
|
19
28
|
|
29
|
+
# Insert fixtures into tables from the yml files in the
|
30
|
+
# "extract_name" fixture set
|
31
|
+
# If you specify a map_models hash here for the last arg like
|
32
|
+
# Post => DifferentPost
|
33
|
+
# It will load the fixtures into a different table than whats listed
|
34
|
+
# in the manifest
|
20
35
|
# NOTE: This is destructive, it will delete everything in the target table
|
21
36
|
#
|
22
|
-
def load_db(extract_name)
|
37
|
+
def load_db(extract_name, map_models={})
|
23
38
|
extractor = Fe::Extractor.new
|
24
39
|
extractor.name = extract_name
|
25
40
|
extractor.load_from_manifest
|
41
|
+
unless map_models.empty?
|
42
|
+
extractor.map_models_hash = map_models
|
43
|
+
end
|
26
44
|
extractor.load_into_database
|
27
45
|
extractor
|
28
46
|
end
|
47
|
+
|
48
|
+
# Rebuilds an existing fixture set from a fe_manifest.yml
|
49
|
+
#
|
29
50
|
def rebuild(extract_name)
|
30
51
|
extractor = Fe::Extractor.new
|
31
52
|
extractor.name = extract_name
|
@@ -33,5 +54,106 @@ module Fe
|
|
33
54
|
extractor.extract
|
34
55
|
extractor
|
35
56
|
end
|
57
|
+
|
58
|
+
|
59
|
+
# Used if you want to get a hash representation of a particular
|
60
|
+
# fixture in a fixture set for a given model
|
61
|
+
#
|
62
|
+
# Used like
|
63
|
+
# h = Fe.get_hash(:first_post_w_comments_and_authors, Post, 'r1')
|
64
|
+
# => {:id => 1, :name => 'first post', ....}
|
65
|
+
# in the console
|
66
|
+
# or in a factory declaration like this
|
67
|
+
#
|
68
|
+
# FactoryGirl.define do
|
69
|
+
# factory :fe4,
|
70
|
+
# :class => Post,
|
71
|
+
# &Fe.get_hash(:first_post_w_comments_and_authors,Post,"r1").to_factory_girl_string.to_proc
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# Kinda meta, but somewhat useful
|
75
|
+
#
|
76
|
+
def get_hash(extract_name, model_name, fixture_name)
|
77
|
+
model_name = model_name.to_s
|
78
|
+
extractor = Fe::Extractor.new
|
79
|
+
extractor.name = extract_name
|
80
|
+
|
81
|
+
begin
|
82
|
+
h=extractor.fixture_hash_for_model(model_name)
|
83
|
+
rescue Exception => e
|
84
|
+
raise "Fe::Extractor#fixture_hash_for_model broke on #{model_name}, perhaps the yml file does exist?"
|
85
|
+
end
|
86
|
+
raise "#{h.inspect} Fe::Extractor#fixture_hash_for_model did not return a hash (broken fixture file)" unless h.kind_of? Hash
|
87
|
+
|
88
|
+
fixture_path_for_model = extractor.fixture_path_for_model(model_name)
|
89
|
+
|
90
|
+
if fixture_name.kind_of? Symbol
|
91
|
+
case fixture_name
|
92
|
+
when :first
|
93
|
+
a_hash = h.to_a.first.last
|
94
|
+
when :last
|
95
|
+
a_hash = h.to_a.last.last
|
96
|
+
else
|
97
|
+
raise "symbols can be :first or :last"
|
98
|
+
end
|
99
|
+
elsif fixture_name.kind_of? String
|
100
|
+
raise "Fixture of the name #{fixture_name} did not exist in in #{fixture_path_for_model}" unless h.has_key?(fixture_name)
|
101
|
+
a_hash = h[fixture_name]
|
102
|
+
else
|
103
|
+
raise "fixture name must be a string or a symbol like :first or :laset"
|
104
|
+
end
|
105
|
+
a_hash.define_singleton_method(:to_factory_girl_string) do
|
106
|
+
s=<<-EOS
|
107
|
+
x = #{model_name}.new(Fe.get_hash(:#{extract_name},#{model_name},"#{fixture_name}"))
|
108
|
+
EOS
|
109
|
+
model_name.constantize.column_names.each do |col|
|
110
|
+
s << "#{col} x.#{col}\n"
|
111
|
+
end
|
112
|
+
s.instance_eval do
|
113
|
+
def to_proc
|
114
|
+
Proc.new {
|
115
|
+
self
|
116
|
+
}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
s
|
120
|
+
end
|
121
|
+
a_hash
|
122
|
+
end
|
123
|
+
|
124
|
+
# Execute the ActiveRecord query associated with the extract set
|
125
|
+
#
|
126
|
+
def execute_extract_code(extract_name)
|
127
|
+
extractor = Fe::Extractor.new
|
128
|
+
extractor.name = extract_name
|
129
|
+
extractor.load_from_manifest
|
130
|
+
extractor.load_input_array_by_executing_extract_code
|
131
|
+
extractor.input_array
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
# Truncate all tables referenced in an extract set
|
136
|
+
#
|
137
|
+
def truncate_tables_for(extract_name)
|
138
|
+
extractor = Fe::Extractor.new
|
139
|
+
extractor.name = extract_name
|
140
|
+
extractor.load_from_manifest
|
141
|
+
extractor.models.each do |model|
|
142
|
+
case ActiveRecord::Base.connection.adapter_name
|
143
|
+
when /mysql|oracle|postgresql/i
|
144
|
+
# Its dumb that this isn't in active record natively
|
145
|
+
# https://github.com/rails/rails/issues/5510
|
146
|
+
ActiveRecord::Base.connection.execute("truncate table #{model.table_name}")
|
147
|
+
else
|
148
|
+
model.delete_all
|
149
|
+
end
|
150
|
+
end
|
151
|
+
true
|
152
|
+
end
|
153
|
+
|
154
|
+
def augment_factory_girl!
|
155
|
+
FactoryGirl::Syntax::Default::DSL.send(:include, Fe::FactoryGirlDslMethods)
|
156
|
+
end
|
36
157
|
end
|
37
158
|
end
|
159
|
+
|
data/lib/fe/extractor.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
module Fe
|
2
2
|
class Extractor
|
3
|
-
attr_accessor :input_array, :extract_code, :name, :row_counts,:table_names
|
3
|
+
attr_accessor :input_array, :extract_code, :name, :row_counts,:table_names, :manifest_hash
|
4
4
|
|
5
5
|
def extract
|
6
|
+
load_input_array_by_executing_extract_code
|
6
7
|
@row_counts = {}
|
7
8
|
@table_names = {}
|
8
9
|
self.output_hash.each_pair do |key,records|
|
@@ -10,47 +11,102 @@ module Fe
|
|
10
11
|
@table_names[key] = key.constantize.table_name
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
+
if File.directory?(self.target_path)
|
15
|
+
FileUtils.remove_dir(self.target_path,:force => true)
|
16
|
+
end
|
14
17
|
FileUtils.mkdir_p(self.target_path)
|
18
|
+
@manifest_hash = {:extract_code => self.extract_code,
|
19
|
+
:name => self.name,
|
20
|
+
:model_names => self.model_names,
|
21
|
+
:row_counts => self.row_counts,
|
22
|
+
:table_names => self.models.map {|m| m.table_name}
|
23
|
+
}
|
15
24
|
File.open(self.manifest_file_path,'w') do |file|
|
16
|
-
file.write(
|
17
|
-
:name => self.name,
|
18
|
-
:model_names => self.model_names,
|
19
|
-
:row_counts => self.row_counts,
|
20
|
-
:table_names => self.models.map {|m| m.table_name}
|
21
|
-
}.to_yaml)
|
25
|
+
file.write(@manifest_hash.to_yaml)
|
22
26
|
end
|
23
27
|
self.write_model_fixtures
|
24
28
|
end
|
25
29
|
|
30
|
+
# This is called from 2 types of invocations
|
31
|
+
# Fe.extract('Post.all', :name => :bla)
|
32
|
+
# or
|
33
|
+
# Fe.extract('[Post.all,Comment.all]', :name => :bla2)
|
34
|
+
#
|
26
35
|
def load_from_args(active_relation_or_array,*args)
|
27
36
|
options = args.extract_options!
|
28
37
|
@name = (options[:name] || Time.now.strftime("%Y_%m_%d_%H_%M_%S")).to_sym
|
29
38
|
if active_relation_or_array.kind_of? String
|
30
39
|
@extract_code = active_relation_or_array
|
31
|
-
@input_array = Array(eval(active_relation_or_array)).to_a
|
32
40
|
else
|
33
|
-
|
34
|
-
@input_array = Array(active_relation_or_array).to_a
|
41
|
+
raise "Extract code must be a string, so .rebuild can be called"
|
35
42
|
end
|
36
43
|
end
|
37
44
|
|
45
|
+
def load_input_array_by_executing_extract_code
|
46
|
+
@input_array = Array(eval(@extract_code)).to_a
|
47
|
+
end
|
48
|
+
|
38
49
|
def load_from_manifest
|
39
50
|
raise "u gotta set .name to use this method" if self.name.blank?
|
40
|
-
|
41
|
-
|
42
|
-
|
51
|
+
@manifest_hash = YAML.load_file(self.manifest_file_path)
|
52
|
+
@extract_code = @manifest_hash[:extract_code]
|
53
|
+
@name = @manifest_hash[:name]
|
54
|
+
@models = @manifest_hash[:model_names].map {|x| x.constantize}
|
55
|
+
end
|
56
|
+
|
57
|
+
def map_models_hash=(map_models_hash)
|
58
|
+
unless (map_models_hash.keys - self.models).empty?
|
59
|
+
raise InvalidSourceModelToMapFrom.new "your map models hash must contain keys representing class names that exist in the fe_manifest.yml"
|
43
60
|
end
|
44
|
-
|
45
|
-
@models = h[:model_names].map {|x| x.constantize}
|
61
|
+
@map_models_hash = map_models_hash
|
46
62
|
end
|
47
63
|
|
64
|
+
def map_models_hash
|
65
|
+
if @map_models_hash.nil?
|
66
|
+
{}
|
67
|
+
else
|
68
|
+
@map_models_hash
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
# Loads data from each fixture file in the extract set using
|
74
|
+
# ActiveRecord::Fixtures
|
75
|
+
#
|
48
76
|
def load_into_database
|
49
77
|
# necessary to make multiple invocations possible in a single test
|
50
78
|
# case possible
|
51
79
|
ActiveRecord::Fixtures.reset_cache
|
52
80
|
self.models.each do |model|
|
53
|
-
|
81
|
+
if self.map_models_hash.has_key?(model)
|
82
|
+
raise "Unfortunately, this is not implemented...from the implementation of .create_fixtures it seems impossible...keeping this code in case its not"
|
83
|
+
h = {model.table_name => self.map_models_hash[model]}
|
84
|
+
ActiveRecord::Fixtures.create_fixtures(self.target_path, model.table_name, h)
|
85
|
+
else
|
86
|
+
ActiveRecord::Fixtures.create_fixtures(self.target_path, model.table_name)
|
87
|
+
end
|
88
|
+
case ActiveRecord::Base.connection.adapter_name
|
89
|
+
when /oracle/i
|
90
|
+
if model.column_names.include? "id"
|
91
|
+
count = model.count
|
92
|
+
sequence_name = model.sequence_name.to_s
|
93
|
+
max_id = model.maximum(:id)
|
94
|
+
next_id = max_id.nil? ? 1 : max_id.to_i + 1
|
95
|
+
begin
|
96
|
+
ActiveRecord::Base.connection.execute("drop sequence #{sequence_name}")
|
97
|
+
rescue
|
98
|
+
puts "[Iron Fixture Extractor] WARNING: couldnt drop the sequence #{sequence_name}, (but who cares!)"
|
99
|
+
end
|
100
|
+
begin
|
101
|
+
q="create sequence #{sequence_name} increment by 1 start with #{next_id}"
|
102
|
+
ActiveRecord::Base.connection.execute(q)
|
103
|
+
rescue
|
104
|
+
puts "[Iron Fixture Extractor] WARNING: couldnt create the sequence #{sequence_name}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
else
|
108
|
+
# Do nothing, only oracle adapters need this
|
109
|
+
end
|
54
110
|
end
|
55
111
|
end
|
56
112
|
# Returns a hash with model class names for keys and Set's of AR
|
@@ -63,7 +119,13 @@ module Fe
|
|
63
119
|
if @output_hash.blank?
|
64
120
|
@output_hash = {}
|
65
121
|
self.input_array.each do |t|
|
66
|
-
|
122
|
+
if t.kind_of?(Array) || t.kind_of?(ActiveRecord::Relation)
|
123
|
+
t.each do |ar_object|
|
124
|
+
recurse(ar_object)
|
125
|
+
end
|
126
|
+
else
|
127
|
+
recurse(t)
|
128
|
+
end
|
67
129
|
end
|
68
130
|
end
|
69
131
|
@output_hash
|
@@ -91,15 +153,38 @@ module Fe
|
|
91
153
|
File.join(self.target_path,"#{model_name.constantize.table_name}.yml")
|
92
154
|
end
|
93
155
|
|
156
|
+
def fixture_hash_for_model(model_name)
|
157
|
+
model_name = model_name.to_s
|
158
|
+
if @fixture_hashes.nil?
|
159
|
+
@fixture_hashes = {}
|
160
|
+
end
|
161
|
+
if @fixture_hashes.has_key?(model_name)
|
162
|
+
@fixture_hashes[model_name]
|
163
|
+
else
|
164
|
+
@fixture_hashes[model_name] = YAML.load_file(self.fixture_path_for_model(model_name))
|
165
|
+
end
|
166
|
+
@fixture_hashes[model_name]
|
167
|
+
end
|
94
168
|
protected
|
95
169
|
|
96
170
|
# Recursively goes over all association_cache's from the record and builds the output_hash
|
97
171
|
# This is the meat-and-potatoes of this tool (plus the the recurse
|
98
172
|
# method) is where something interesting is happening
|
173
|
+
#
|
174
|
+
# TODO: To work with ActiveRecord 2.3.x, we'll need to recurse using this logic: (from activerecord-2.3.14/lib/active_record/associations.rb)
|
175
|
+
# # Clears out the association cache
|
176
|
+
# def clear_association_cache #:nodoc:
|
177
|
+
# self.class.reflect_on_all_associations.to_a.each do |assoc|
|
178
|
+
# instance_variable_set "@#{assoc.name}", nil
|
179
|
+
# end unless self.new_record?
|
180
|
+
# end
|
181
|
+
#
|
182
|
+
#
|
99
183
|
def recurse(record)
|
100
184
|
raise "This gem only knows how to extract stuff w ActiveRecord" unless record.kind_of? ActiveRecord::Base
|
101
|
-
|
102
|
-
@output_hash[
|
185
|
+
key = record.class.base_class.to_s # the base_class is key for correctly handling STI
|
186
|
+
@output_hash[key] ||= Set.new # Set ensures no duplicates
|
187
|
+
@output_hash[key].add record
|
103
188
|
record.association_cache.each do |assoc_cache|
|
104
189
|
assoc_name = assoc_cache.first
|
105
190
|
assoc_value = assoc_cache.last.target
|
@@ -123,6 +208,10 @@ module Fe
|
|
123
208
|
# Array() bit done to support composite primary keys
|
124
209
|
fixture_name = "r#{Array(record.id).join('_')}"
|
125
210
|
hash[fixture_name] = record.attributes
|
211
|
+
# dump serialized attributes
|
212
|
+
record.serialized_attributes.each do |attr, serializer|
|
213
|
+
hash[fixture_name][attr] = serializer.dump(hash[fixture_name][attr])
|
214
|
+
end
|
126
215
|
hash
|
127
216
|
}.to_yaml
|
128
217
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Fe
|
2
|
+
module FactoryGirlDslMethods
|
3
|
+
def fe_factory(name, options = {})
|
4
|
+
unless extract_name = options.delete(:extract_name)
|
5
|
+
raise "Must specify extract_name (the fixture set name)"
|
6
|
+
end
|
7
|
+
unless fixture_name = options.delete(:fixture_name)
|
8
|
+
raise "Must specify fixture_name" # TODO:Later, make this default to :first once impelmented in Fe
|
9
|
+
end
|
10
|
+
unless options.has_key?(:class)
|
11
|
+
raise "Must specify the class when using with iron fixture extractor"
|
12
|
+
end
|
13
|
+
|
14
|
+
# CONTINUE HERE. We need to figure out how to build a
|
15
|
+
# block for Factory girl from the hash that lives in the yaml.
|
16
|
+
#
|
17
|
+
fe_hash = Fe.get_hash(extract_name, options[:class],fixture_name)
|
18
|
+
|
19
|
+
the_block = Proc.new {
|
20
|
+
}
|
21
|
+
|
22
|
+
factory(name,options,&the_block)
|
23
|
+
|
24
|
+
factory_inst = ::FactoryGirl.factory_by_name(name)
|
25
|
+
# require 'debugger'; debugger; puts 'DSLExt'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/fe/railtie.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
namespace :iron_fixture_extractor do
|
2
|
+
desc "Executes Fe.rebuild(extract_name) to re-create an existing fixture file set"
|
3
|
+
task :rebuild, [:extract_name] => :environment do |t,args|
|
4
|
+
Fe.rebuild(args[:extract_name].to_sym)
|
5
|
+
end
|
6
|
+
|
7
|
+
desc "Executes Fe.load_db(extract_name) to insert rows associated with file set"
|
8
|
+
task :load_db, [:extract_name] => :environment do |t,args|
|
9
|
+
Fe.load_db(args[:extract_name].to_sym)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
data/lib/fe/version.rb
CHANGED
data/test/basic_usage_test.rb
CHANGED
@@ -20,10 +20,12 @@ class BasicUsage < ActiveSupport::TestCase
|
|
20
20
|
assert_equal Post.table_name, extractor.table_names['Post']
|
21
21
|
assert File.exists?(File.join(Fe.fixtures_root,'first_post_w_comments_and_authors','fe_manifest.yml')), "The file that allows the fixtures to get rebuilt"
|
22
22
|
assert_equal 1, extractor.row_counts['Post']
|
23
|
+
assert_equal 1, extractor.row_counts['Author']
|
24
|
+
assert_kind_of Hash, extractor.manifest_hash
|
23
25
|
assert File.exists?(File.join(Fe.fixtures_root,'first_post_w_comments_and_authors',"#{Post.table_name}.yml")), "The file is created"
|
24
26
|
end
|
25
27
|
end
|
26
|
-
context ".load_db" do
|
28
|
+
context ".load_db, .execute_extract_code" do
|
27
29
|
setup do
|
28
30
|
FeTestEnv.setup # regular production db
|
29
31
|
extract_hash = Fe.extract(@extract_code, :name => @extract_name)
|
@@ -42,6 +44,12 @@ class BasicUsage < ActiveSupport::TestCase
|
|
42
44
|
assert_equal 1, Comment.count
|
43
45
|
assert_equal 1, Author.count
|
44
46
|
end
|
47
|
+
should "provide the ability to execute the same query that built the fixtures" do
|
48
|
+
Fe.load_db(@extract_name)
|
49
|
+
rows = Fe.execute_extract_code(:first_post_w_comments_and_authors)
|
50
|
+
assert_equal 1, rows.length
|
51
|
+
assert (rows.first.association_cache.keys - [:comments,:author]).empty?, "Comments and authors should be eager loaded"
|
52
|
+
end
|
45
53
|
end
|
46
54
|
context ".rebuild" do
|
47
55
|
setup do
|
@@ -49,7 +57,7 @@ class BasicUsage < ActiveSupport::TestCase
|
|
49
57
|
@extractor = Fe.extract(@extract_code, :name => @extract_name)
|
50
58
|
end
|
51
59
|
teardown do
|
52
|
-
|
60
|
+
FeTestEnv.teardown
|
53
61
|
end
|
54
62
|
should "be able to rebuild the fixture files from the manifest" do
|
55
63
|
# TODO: continue here, should delete a comment, then rebuild,
|
@@ -66,21 +74,33 @@ class BasicUsage < ActiveSupport::TestCase
|
|
66
74
|
#assert_equal 0, Post.count
|
67
75
|
end
|
68
76
|
end
|
77
|
+
|
78
|
+
context ".truncate_tables_for" do
|
79
|
+
setup do
|
80
|
+
FeTestEnv.setup # regular production db
|
81
|
+
extract_hash = Fe.extract(@extract_code, :name => @extract_name)
|
82
|
+
FeTestEnv.the_env = 'fake_test'
|
83
|
+
FeTestEnv.recreate_schema_without_data
|
84
|
+
end
|
85
|
+
teardown do
|
86
|
+
FeTestEnv.teardown
|
87
|
+
end
|
88
|
+
should "truncate only the tables in the fixture set" do
|
89
|
+
Group.create
|
90
|
+
assert_equal 1, Group.count
|
91
|
+
|
92
|
+
Fe.load_db(@extract_name)
|
93
|
+
assert_equal 1, Post.count
|
94
|
+
assert_equal 1, Comment.count
|
95
|
+
assert_equal 1, Author.count
|
96
|
+
|
97
|
+
Fe.truncate_tables_for(@extract_name)
|
98
|
+
assert_equal 1, Group.count
|
99
|
+
assert_equal 0, Post.count
|
100
|
+
assert_equal 0, Comment.count
|
101
|
+
assert_equal 0, Author.count
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
69
105
|
end
|
70
|
-
# NOT SURE IF THESE MATTER, probably do..commented out for now
|
71
|
-
#context "2nd tier API" do
|
72
|
-
#should "provide an extractor class" do
|
73
|
-
#extract_code = Post.first
|
74
|
-
#e=Fe::Extractor.new
|
75
|
-
#e.input_array = [extract_code]
|
76
|
-
#assert_kind_of Hash, e.output_hash
|
77
|
-
#assert_equal Post, e.output_hash.keys.first
|
78
|
-
#assert_equal extract_code, e.output_hash[Post].first
|
79
|
-
#end
|
80
|
-
#should "work with recursive loading" do
|
81
|
-
#e=Fe::Extractor.new
|
82
|
-
#e.input_array = Post.includes(:comments, :author)
|
83
|
-
#assert (e.output_hash.keys - [Post,Comment,Author]).empty?, "There are only keys for the eager loaded models"
|
84
|
-
#end
|
85
|
-
#end
|
86
106
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# This test ensures that you can load_db into a different table/model
|
2
|
+
# than the one you extracted from
|
3
|
+
#
|
4
|
+
# THIS IS NOT COMPLETE, it seems like its impossible if you want to use
|
5
|
+
# ActiveRecord's .create_fixtures method...talk to Joe if you really
|
6
|
+
# need this feature
|
7
|
+
#
|
8
|
+
require 'test_helper'
|
9
|
+
class DfferentTargetTableTest < ActiveSupport::TestCase
|
10
|
+
#setup do
|
11
|
+
#@extract_code = 'Post.includes(:comments, :author).limit(1)'
|
12
|
+
#@extract_name = :first_post_w_comments_and_authors
|
13
|
+
#FeTestEnv.setup # regular production db
|
14
|
+
#extract_hash = Fe.extract(@extract_code, :name => @extract_name)
|
15
|
+
#FeTestEnv.the_env = 'fake_test'
|
16
|
+
#FeTestEnv.recreate_schema_without_data
|
17
|
+
#end
|
18
|
+
#teardown do
|
19
|
+
#FeTestEnv.teardown
|
20
|
+
#end
|
21
|
+
#should "provide the ability to load fixtures" do
|
22
|
+
#assert_equal 0, Post.count
|
23
|
+
#assert_equal 0, ::DifferentPost.count
|
24
|
+
#assert_raise Fe::InvalidSourceModelToMapFrom do
|
25
|
+
## should fail cause User is not in the fixture set
|
26
|
+
#extractor = Fe.load_db(@extract_name, User => Post)
|
27
|
+
#end
|
28
|
+
## extractor = Fe.load_db(@extract_name, Post => ::DifferentPost)
|
29
|
+
#require 'debugger'; debugger; puts 's'
|
30
|
+
#puts "TODO: CONTINUE HERE WITH BUILDING THE CODE TO MAKE THE FOLLOWING 2 ASSERT STATEMENTS PASS"
|
31
|
+
##assert_equal 0, Post.count
|
32
|
+
##assert_equal 1, DifferentPost.count
|
33
|
+
##assert_equal 1, Author.count
|
34
|
+
#end
|
35
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# WARNING: THIS IS AN EXPERIMENTAL FEATURE THAT ISN'T QUITE COMPLETE AND MIGHT BE DEPRECATED
|
2
|
+
# WARNING: THIS IS AN EXPERIMENTAL FEATURE THAT ISN'T QUITE COMPLETE AND MIGHT BE DEPRECATED
|
3
|
+
# WARNING: THIS IS AN EXPERIMENTAL FEATURE THAT ISN'T QUITE COMPLETE AND MIGHT BE DEPRECATED
|
4
|
+
# WARNING: THIS IS AN EXPERIMENTAL FEATURE THAT ISN'T QUITE COMPLETE AND MIGHT BE DEPRECATED
|
5
|
+
require 'test_helper'
|
6
|
+
require 'factory_girl'
|
7
|
+
class FactoryGirlTest < ActiveSupport::TestCase
|
8
|
+
setup do
|
9
|
+
|
10
|
+
@extract_code = 'Post.includes(:comments, :author).limit(1)'
|
11
|
+
@extract_name = :first_post_w_comments_and_authors
|
12
|
+
FeTestEnv.setup # regular production db
|
13
|
+
Fe.extract(@extract_code, :name => @extract_name) # build fixture yml
|
14
|
+
FeTestEnv.the_env = 'fake_test'
|
15
|
+
FeTestEnv.recreate_schema_without_data
|
16
|
+
|
17
|
+
@post_hash = Fe.get_hash(:first_post_w_comments_and_authors, Post,"r1")
|
18
|
+
|
19
|
+
|
20
|
+
end
|
21
|
+
should "expose a .to_factory_girl_string method" do
|
22
|
+
assert_kind_of Hash, @post_hash
|
23
|
+
assert_respond_to @post_hash, :to_factory_girl_string
|
24
|
+
assert !Hash.instance_methods.include?(:to_factory_girl_string)
|
25
|
+
|
26
|
+
@fg_string = @post_hash.to_factory_girl_string
|
27
|
+
assert_match /Post/, @fg_string, "The string should have the model name on the first line"
|
28
|
+
end
|
29
|
+
|
30
|
+
should ".to_factory_girl_string should return a monkey patched string implementing .to_proc" do
|
31
|
+
@fg_string = @post_hash.to_factory_girl_string
|
32
|
+
assert_respond_to @fg_string, :to_proc
|
33
|
+
end
|
34
|
+
|
35
|
+
should "be just like a factory produced in a non-meta way" do
|
36
|
+
FactoryGirl.define do
|
37
|
+
# This is the essense of the code that .to_factory_girl_string spits out
|
38
|
+
factory :fe2, :class => Post do
|
39
|
+
x = Post.new(Fe.get_hash(:first_post_w_comments_and_authors,Post,"r1"))
|
40
|
+
id x.id
|
41
|
+
author_id x.author_id
|
42
|
+
name x.name
|
43
|
+
content x.content
|
44
|
+
serialized_thing x.serialized_thing
|
45
|
+
created_at x.created_at
|
46
|
+
updated_at x.updated_at
|
47
|
+
end
|
48
|
+
|
49
|
+
# We are evaluating the to_factory_girl_string in the block context factory girl
|
50
|
+
# if you wanted to override settings you could do so afterwords
|
51
|
+
factory :fe3, :class => Post, &Proc.new {
|
52
|
+
self.instance_eval(Fe.get_hash(:first_post_w_comments_and_authors,Post,"r1").to_factory_girl_string)
|
53
|
+
# I think You could override attributes set in the fixture here, like:
|
54
|
+
# name "poo poo"
|
55
|
+
}
|
56
|
+
|
57
|
+
# This is two levels meta-ness away
|
58
|
+
factory :fe4,
|
59
|
+
:class => Post,
|
60
|
+
&Fe.get_hash(:first_post_w_comments_and_authors,Post,"r1").to_factory_girl_string.to_proc
|
61
|
+
end
|
62
|
+
|
63
|
+
@fe2 = FactoryGirl.create(:fe2)
|
64
|
+
assert_kind_of Post, @fe2
|
65
|
+
|
66
|
+
@fe3 = FactoryGirl.create(:fe3)
|
67
|
+
assert_kind_of Post, @fe3
|
68
|
+
assert_kind_of Time, @fe3.updated_at, "Objects get the right type"
|
69
|
+
|
70
|
+
@fe4 = FactoryGirl.create(:fe4)
|
71
|
+
assert_kind_of Post, @fe4
|
72
|
+
assert_kind_of Time, @fe4.updated_at, "Objects get the right type"
|
73
|
+
end
|
74
|
+
teardown do
|
75
|
+
FeTestEnv.teardown
|
76
|
+
end
|
77
|
+
end
|
data/test/fe_test_env.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class FeTestEnv
|
2
2
|
class << self
|
3
3
|
def models
|
4
|
-
[:post,:comment,:author,:group,:group_member]
|
4
|
+
[:serialized_attribute_encoder,:complex_thing,:post,:comment,:author,:group,:group_member,:different_post, :user, :'user/admin',:'user/jerk']
|
5
5
|
end
|
6
6
|
def model_classes
|
7
7
|
self.models.map {|x| x.to_s.classify.constantize}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class GetHashTest < ActiveSupport::TestCase
|
3
|
+
context "Fe" do
|
4
|
+
setup do
|
5
|
+
FeTestEnv.setup
|
6
|
+
@extract_code = 'Post.includes(:comments, :author).limit(1)'
|
7
|
+
@extract_name = :first_post_w_comments_and_authors
|
8
|
+
extractor = Fe.extract(@extract_code, :name => @extract_name)
|
9
|
+
end
|
10
|
+
context ".extract" do
|
11
|
+
should "have a .get_hash method" do
|
12
|
+
assert_respond_to Fe, :get_hash
|
13
|
+
end
|
14
|
+
context ".get_hash behavior" do
|
15
|
+
should "return a hash with the right columns" do
|
16
|
+
h = Fe.get_hash(:first_post_w_comments_and_authors, Post, 'r1')
|
17
|
+
assert_kind_of Hash, h
|
18
|
+
assert_equal 1, h["id"]
|
19
|
+
assert_equal "First post", h["name"]
|
20
|
+
assert_equal "ComplexThing", h["serialized_thing"]
|
21
|
+
|
22
|
+
# allow :first to grab the first fixture, so you don't have to know the name
|
23
|
+
h2 = Fe.get_hash(:first_post_w_comments_and_authors, Post, :first)
|
24
|
+
assert_equal h, h2
|
25
|
+
|
26
|
+
h3 = Fe.get_hash(:first_post_w_comments_and_authors, Post, :last)
|
27
|
+
assert_equal h, h3, "there is only one fixture in this set to last is the same as first"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
teardown do
|
32
|
+
FeTestEnv.teardown
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateDifferentPosts < ActiveRecord::Migration
|
2
|
+
# DUPLICATED FROM Posts
|
3
|
+
def change
|
4
|
+
create_table :different_posts do |t|
|
5
|
+
t.belongs_to :author
|
6
|
+
t.string :name
|
7
|
+
t.string :content
|
8
|
+
t.string :serialized_thing
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
add_index :different_posts, :author_id
|
13
|
+
end
|
14
|
+
end
|
data/test/models/group.rb
CHANGED
data/test/models/post.rb
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
# This encoder just serializes complex attributes with the string
|
2
|
+
# representation of their class. A +ComplexThing+ instance is stored in
|
3
|
+
# the database as 'ComplexThing', not a marshalled Ruby object.
|
4
|
+
#
|
5
|
+
class SerializedAttributeEncoder
|
6
|
+
def load(value)
|
7
|
+
value.constantize.new
|
8
|
+
end
|
9
|
+
def dump(object)
|
10
|
+
object.class.to_s
|
11
|
+
end
|
12
|
+
end
|
data/test/models/user.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class MultiTreeUsageTest < ActiveSupport::TestCase
|
3
|
+
context "Multi Tree Usage" do
|
4
|
+
setup do
|
5
|
+
@extract_code = '[Post.includes(:comments).limit(1),Author.all]'
|
6
|
+
@extract_name = :two_tree
|
7
|
+
end
|
8
|
+
context ".extract" do
|
9
|
+
setup do
|
10
|
+
FeTestEnv.setup
|
11
|
+
end
|
12
|
+
teardown do
|
13
|
+
# FeTestEnv.teardown
|
14
|
+
end
|
15
|
+
should "provide the right output, and put the file in the right place" do
|
16
|
+
extractor = Fe.extract(@extract_code, :name => @extract_name)
|
17
|
+
assert (%w(Post Comment Author) - extractor.model_names).empty?, "only these keys should exist"
|
18
|
+
assert File.exists?(File.join(Fe.fixtures_root,'two_tree','fe_manifest.yml')), "The file that allows the fixtures to get rebuilt"
|
19
|
+
assert_equal 1, extractor.row_counts['Post']
|
20
|
+
assert_equal 2, extractor.row_counts['Author']
|
21
|
+
#assert File.exists?(File.join(Fe.fixtures_root,'first_post_w_comments_and_authors',"#{Post.table_name}.yml")), "The file is created"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class SerializedAttributeTest < ActiveSupport::TestCase
|
3
|
+
context "A model with a serialized attribute" do
|
4
|
+
setup do
|
5
|
+
@extract_code = 'Post.limit(1)'
|
6
|
+
@extract_name = :posts_with_serialized_thing
|
7
|
+
end
|
8
|
+
context ".extract and .load_db with serialized attributes" do
|
9
|
+
setup do
|
10
|
+
FeTestEnv.setup
|
11
|
+
Fe.extract(@extract_code, :name => @extract_name)
|
12
|
+
FeTestEnv.the_env = 'fake_test'
|
13
|
+
FeTestEnv.recreate_schema_without_data
|
14
|
+
end
|
15
|
+
teardown do
|
16
|
+
FeTestEnv.teardown
|
17
|
+
end
|
18
|
+
should "extract the .dump() value of the serialized attribute" do
|
19
|
+
Fe.load_db(@extract_name)
|
20
|
+
if Post.count == 0
|
21
|
+
raise "The test setup didn't work, Post.count should have some rows"
|
22
|
+
end
|
23
|
+
assert_kind_of ComplexThing, Post.first.serialized_thing
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/test/sti_test.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class StiTest < ActiveSupport::TestCase
|
3
|
+
setup do
|
4
|
+
FeTestEnv.setup
|
5
|
+
@extract_code = 'User.where("1=1")'
|
6
|
+
@extract_name = :all_users
|
7
|
+
end
|
8
|
+
teardown do
|
9
|
+
FeTestEnv.teardown
|
10
|
+
end
|
11
|
+
should "yo" do
|
12
|
+
extractor = Fe.extract(@extract_code, :name => @extract_name)
|
13
|
+
assert_equal [User], extractor.models
|
14
|
+
assert_equal({'User' => 2}, extractor.row_counts)
|
15
|
+
FeTestEnv.the_env = 'fake_test'
|
16
|
+
FeTestEnv.recreate_schema_without_data
|
17
|
+
Fe.load_db(@extract_name)
|
18
|
+
assert_equal ["User::Admin", "User::Jerk"], User.all.map(&:type).sort
|
19
|
+
end
|
20
|
+
end
|
@@ -1,14 +1,17 @@
|
|
1
1
|
class CreateSomeData < ActiveRecord::Migration
|
2
2
|
def up
|
3
|
-
a=Author.create name
|
4
|
-
p1=a.posts.create name
|
5
|
-
p1.comments.create content
|
6
|
-
p2=a.posts.create name
|
7
|
-
p2.comments.create content
|
3
|
+
a=Author.create :name => "Joe"
|
4
|
+
p1=a.posts.create :name => "First post", :serialized_thing => ComplexThing.new
|
5
|
+
p1.comments.create :content => "This is crap"
|
6
|
+
p2=a.posts.create :name => "Second post", :serialized_thing => ComplexThing.new
|
7
|
+
p2.comments.create :content => "This is great"
|
8
8
|
|
9
|
-
a2=Author.create name
|
10
|
-
g=Group.create name
|
9
|
+
a2=Author.create :name => "Bill"
|
10
|
+
g=Group.create :name => "Group 1"
|
11
11
|
g.authors << a2
|
12
12
|
g.save
|
13
|
+
|
14
|
+
User::Jerk.create(:name => "Jimmy the jerk")
|
15
|
+
User::Admin.create(:name => "Ron the admin")
|
13
16
|
end
|
14
17
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: iron_fixture_extractor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 1.0.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Joe Goggins
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-11-30 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -56,6 +56,17 @@ dependencies:
|
|
56
56
|
version: "0"
|
57
57
|
type: :development
|
58
58
|
version_requirements: *id004
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: factory_girl
|
61
|
+
prerelease: false
|
62
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
type: :development
|
69
|
+
version_requirements: *id005
|
59
70
|
description: "When object factories don't work because your data is too complex and creating manual fixtures is cumbersome and brittle: Iron Fixture Extractor (for Rails/ActiveRecord) "
|
60
71
|
email:
|
61
72
|
- goggins@umn.edu
|
@@ -67,6 +78,7 @@ extra_rdoc_files: []
|
|
67
78
|
|
68
79
|
files:
|
69
80
|
- .gitignore
|
81
|
+
- CHANGELOG.md
|
70
82
|
- Gemfile
|
71
83
|
- LICENSE
|
72
84
|
- README.md
|
@@ -74,21 +86,38 @@ files:
|
|
74
86
|
- iron_fixture_extractor.gemspec
|
75
87
|
- lib/fe.rb
|
76
88
|
- lib/fe/extractor.rb
|
89
|
+
- lib/fe/factory_girl_dsl_methods.rb
|
90
|
+
- lib/fe/railtie.rb
|
91
|
+
- lib/fe/tasks/iron_fixture_extractor.rake
|
77
92
|
- lib/fe/version.rb
|
78
93
|
- lib/iron_fixture_extractor.rb
|
79
94
|
- test/basic_usage_test.rb
|
80
95
|
- test/config/database.yml
|
96
|
+
- test/different_target_table_test.rb
|
97
|
+
- test/factory_girl_test.rb
|
81
98
|
- test/fe_test_env.rb
|
99
|
+
- test/get_hash_test.rb
|
82
100
|
- test/migrations/20120604043601_create_posts.rb
|
83
101
|
- test/migrations/20120604043602_create_authors.rb
|
102
|
+
- test/migrations/20120604043603_create_different_posts.rb
|
84
103
|
- test/migrations/20120604043639_create_comments.rb
|
85
104
|
- test/migrations/20120604043808_create_group_members.rb
|
86
105
|
- test/migrations/20120604043818_create_groups.rb
|
106
|
+
- test/migrations/20120604043819_create_users.rb
|
87
107
|
- test/models/author.rb
|
88
108
|
- test/models/comment.rb
|
109
|
+
- test/models/complex_thing.rb
|
110
|
+
- test/models/different_post.rb
|
89
111
|
- test/models/group.rb
|
90
112
|
- test/models/group_member.rb
|
91
113
|
- test/models/post.rb
|
114
|
+
- test/models/serialized_attribute_encoder.rb
|
115
|
+
- test/models/user.rb
|
116
|
+
- test/models/user/admin.rb
|
117
|
+
- test/models/user/jerk.rb
|
118
|
+
- test/multi_tree_usage_test.rb
|
119
|
+
- test/serialized_attribute_test.rb
|
120
|
+
- test/sti_test.rb
|
92
121
|
- test/test_data_migrations/001_create_some_data.rb
|
93
122
|
- test/test_helper.rb
|
94
123
|
homepage: https://github.com/joegoggins/iron_fixture_extractor
|
@@ -114,23 +143,37 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
143
|
requirements: []
|
115
144
|
|
116
145
|
rubyforge_project:
|
117
|
-
rubygems_version: 1.8.
|
146
|
+
rubygems_version: 1.8.15
|
118
147
|
signing_key:
|
119
148
|
specification_version: 3
|
120
149
|
summary: Simplified dynamic fixture extraction for ActiveRecord
|
121
150
|
test_files:
|
122
151
|
- test/basic_usage_test.rb
|
123
152
|
- test/config/database.yml
|
153
|
+
- test/different_target_table_test.rb
|
154
|
+
- test/factory_girl_test.rb
|
124
155
|
- test/fe_test_env.rb
|
156
|
+
- test/get_hash_test.rb
|
125
157
|
- test/migrations/20120604043601_create_posts.rb
|
126
158
|
- test/migrations/20120604043602_create_authors.rb
|
159
|
+
- test/migrations/20120604043603_create_different_posts.rb
|
127
160
|
- test/migrations/20120604043639_create_comments.rb
|
128
161
|
- test/migrations/20120604043808_create_group_members.rb
|
129
162
|
- test/migrations/20120604043818_create_groups.rb
|
163
|
+
- test/migrations/20120604043819_create_users.rb
|
130
164
|
- test/models/author.rb
|
131
165
|
- test/models/comment.rb
|
166
|
+
- test/models/complex_thing.rb
|
167
|
+
- test/models/different_post.rb
|
132
168
|
- test/models/group.rb
|
133
169
|
- test/models/group_member.rb
|
134
170
|
- test/models/post.rb
|
171
|
+
- test/models/serialized_attribute_encoder.rb
|
172
|
+
- test/models/user.rb
|
173
|
+
- test/models/user/admin.rb
|
174
|
+
- test/models/user/jerk.rb
|
175
|
+
- test/multi_tree_usage_test.rb
|
176
|
+
- test/serialized_attribute_test.rb
|
177
|
+
- test/sti_test.rb
|
135
178
|
- test/test_data_migrations/001_create_some_data.rb
|
136
179
|
- test/test_helper.rb
|