Created
January 3, 2015 20:24
-
-
Save stellard/c87d1007590b13256f38 to your computer and use it in GitHub Desktop.
KujiFixtureLoader "name to be changed"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#The locations and naming of these files is by convention spec/fixtures/fixture_loader/*_fixture.rb | |
let(:bin_group) { Fabricate(:bin_group) } | |
let(:external_bin) { Fabricate(:bin_type, bin_group: bin_group, :is_external => true) } | |
let(:internal_bin1) { Fabricate(:bin_type, bin_group: bin_group, :is_external => false) } | |
let(:internal_bin2) { Fabricate(:bin_type, bin_group: bin_group, :is_external => false) } | |
let(:postpaid_bag) { Fabricate(:bin_type, bin_group: bin_group, :is_bag => true, :charged_on_delivery => false) } | |
let(:prepaid_bag) { Fabricate(:bin_type, bin_group: bin_group, :is_bag => true, :charged_on_delivery => true) } | |
let(:service_fee1) { Fabricate(:service_fee) } | |
let(:service_fee2) { Fabricate(:service_fee) } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
describe 'example' do | |
#-Loads the example_fixture.rb into the database in a before all | |
#-Adds let blocks for everything in the fixture | |
#-Users database cleaner to set transactions as the cleaning strategy | |
#-Resets back to the loaded fixtures on each run | |
load_fixtures :example | |
it "should have access to the let blocks" do | |
bin_group.should_not be_nil | |
postpaid_bag.should_not be_nil | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module KujiRspecFixtureLoader | |
module ExampleMethods | |
def dump_all_fixtures | |
KujiFixture.all.each do |fixture| | |
fixture.refresh_fixtures if fixture.expired? | |
end | |
end | |
end | |
module ExampleGroupMethods | |
def load_fixtures fixture | |
unless respond_to?(:metadata) && metadata[:broken] | |
before(:all) do | |
KujiFixture[fixture].refresh_fixtures if KujiFixture[fixture].expired? | |
KujiFixture[fixture].load_fixtures | |
end | |
after(:all) do | |
DatabaseCleaner[:active_record].clean_with(:truncation) | |
end | |
KujiFixture[fixture].object_store.methods.each do |name| | |
let(name) { KujiFixture[fixture].object_store[name] } | |
end | |
end | |
end | |
end | |
def self.included(mod) | |
mod.extend ExampleGroupMethods | |
mod.__send__ :include, ExampleMethods | |
end | |
end | |
class KujiFixture | |
attr_accessor :name | |
def initialize name | |
`mkdir -p #{input_dir}` | |
`mkdir -p #{output_dir}` | |
@name = name | |
end | |
class << self | |
def directory | |
@directory ||= Hash[*Dir['spec/fixtures/fixture_loader/input/**/*.rb'].map { |d| File.basename(d)[/(.+)_fixture\.rb\z/, 1].to_sym }.map { |name| [name, KujiFixture.new(name)] }.flatten] | |
end | |
def all | |
directory.values | |
end | |
def [] name | |
directory[name] | |
end | |
end | |
def refresh_fixtures | |
puts "Dumping Fixture #{name}" | |
run_and_dump_fixtures | |
end | |
def load_fixtures | |
port = db_config[:port] | |
`psql -d #{db_config[:database]} -f #{fixture_output_file_path} -U #{db_config[:username]}#{" -p #{port}" unless port.blank?} -h #{db_config[:host]} > /dev/null` | |
end | |
def expired? | |
#return true | |
#debugger | |
last_schema_digest != RuntimeStats.latest_schema_digest || | |
last_run.nil? || last_modified > last_run || | |
!(File.exists?(fixture_output_file_path) && File.exists?(object_map_file_path)) | |
end | |
def object_map | |
begin | |
@object_map ||= YAML.load_file(object_map_file_path) | |
rescue Errno::ENOENT | |
run_and_dump_fixtures | |
retry | |
end | |
end | |
class StoreProxy | |
attr_reader :methods | |
def initialize object_map | |
object_map.each_pair do |name, hash| | |
if hash[:type] == "db" | |
instance_eval "def #{name}; #{hash[:class]}.find('#{hash[:id]}'); end" | |
elsif hash[:type] == "serialized" | |
instance_eval "def #{name}; YAML::load('#{hash[:data]}'); end" | |
elsif hash[:type] == "money" | |
instance_eval "def #{name}; Money.new(#{hash[:fractional]}, '#{hash[:currency]}'); end" | |
else | |
raise "Unknow object type: #{hash[:type]} in Fixture #{fixture}" | |
end | |
end | |
@methods = object_map.keys | |
end | |
def [] name | |
send(name) if respond_to?(name) | |
rescue => e | |
#debugger | |
raise e | |
end | |
end | |
def object_store | |
@object_store ||= StoreProxy.new(object_map) | |
end | |
private | |
def dump_fixtures | |
port = db_config[:port] | |
`pg_dump --disable-triggers -T "schema_migrations" -T "audit.logged_actions" -U #{db_config[:username]}#{" -p #{port}" unless port.blank?} -h #{db_config[:host]} -a #{db_config[:database]} > #{fixture_output_file_path}` | |
end | |
def run_and_dump_fixtures | |
clean_db | |
#debugger | |
puts "Running fixture file: #{fixture_input_file_path}" | |
#debugger | |
eval_proxy.run | |
#debugger | |
dump_fixtures | |
#debugger | |
dump_object_map | |
store_last_run | |
#debugger | |
clean_db | |
end | |
def clean_db | |
DatabaseCleaner[:active_record].clean_with(:truncation) | |
#PgAudit::LoggedAction.delete_all | |
end | |
def last_modified | |
File.mtime(fixture_input_file_path) | |
end | |
def db_config | |
User.connection_config | |
end | |
def eval_proxy | |
@eval_proxy ||= EvalProxy.new fixture_input_file_path | |
end | |
def dump_object_map | |
puts "Warning: Cannot dump object hash since it is empty" if eval_proxy.object_hash.blank? | |
new_object_map = {} | |
eval_proxy.object_hash.each_pair do |key, value| | |
if value.class.respond_to?(:find) && value.respond_to?(:id) | |
new_object_map[key] = { :id => value.id, :class => value.class.to_s, :type => "db" } | |
elsif value.is_a?(Money) | |
new_object_map[key] = { :fractional => value.fractional, :currency => value.currency.to_s, :type => "money" } | |
else | |
new_object_map[key] = { :data => YAML::dump(value), :type => "serialized" } | |
end | |
end | |
File.open(object_map_file_path, 'w+') {|f| f.write(new_object_map.to_yaml) } | |
@object_map = new_object_map | |
end | |
def fixture_output_file_path | |
output_dir("#{name}_fixture.sql").to_s | |
end | |
def object_map_file_path | |
output_dir("#{name}_object_map.yml").to_s | |
end | |
def fixture_input_file_path | |
input_dir("#{name}_fixture.rb").to_s | |
end | |
def store_last_run | |
RuntimeStats.store(name, Time.now) | |
end | |
def last_run | |
RuntimeStats.last_modified name | |
end | |
def last_schema_digest | |
RuntimeStats.schema_digest name | |
end | |
def output_dir name = '' | |
Rails.root.join('spec/fixtures/fixture_loader/output', name) | |
end | |
def input_dir name = '' | |
Rails.root.join('spec/fixtures/fixture_loader/input', name) | |
end | |
class EvalProxy | |
attr_reader :file_path | |
def initialize file_path | |
@file_path = file_path | |
end | |
def let name, &block | |
raise "Already defined let(:#{name}) for fixture '#{file_path}'" unless proc_hash[name].nil? | |
(proc_hash[name] = block).tap { define_method_for(name) } | |
end | |
alias :let! :let | |
def run | |
eval(::File.open(file_path).read, binding, file_path) | |
eval_procs | |
end | |
def object_hash | |
@object_hash ||= {} | |
end | |
private | |
def define_method_for name | |
instance_eval %| | |
def #{name} | |
get(:#{name}) | |
end | |
| | |
end | |
def get name | |
return object_hash[name] if object_hash[name] | |
if proc_hash[name] | |
object_hash[name] = proc_hash[name].call | |
else | |
raise "fixture not found with name #{name}" | |
end | |
end | |
def eval_procs | |
proc_hash.keys.each { |name| get name } | |
end | |
def proc_hash | |
@proc_hash ||= {} | |
end | |
end | |
class RuntimeStats | |
class << self | |
def store name, time | |
(data(name)[:last_modified] = time).tap do | |
data(name)[:schema_digest] = latest_schema_digest | |
persist | |
end | |
end | |
def schema_digest name | |
data(name)[:schema_digest] | |
end | |
def last_modified name | |
data(name)[:last_modified] | |
end | |
def file_path | |
Rails.root.join('spec/fixtures/fixture_loader/', "runtime_stats.yml").to_s | |
end | |
def latest_schema_digest | |
Digest::MD5.hexdigest(ActiveRecord::SchemaMigration.pluck(:version).sort.join) | |
end | |
def persist | |
File.open(file_path, 'w+') {|f| f.write(@data.to_yaml) } | |
end | |
def data name | |
begin | |
@data ||= YAML.load_file(file_path) | |
raise("#{file_path} is not a valid yaml file, you can delete it and it will be regenerated") unless @data | |
name.blank? ? @data : @data[name] ||= {} | |
rescue Errno::ENOENT | |
write_blank_file | |
retry | |
end | |
end | |
private | |
def write_blank_file | |
File.open(file_path, 'w+') {|f| f.write({}.to_yaml) } | |
end | |
end | |
end | |
end | |
RSpec.configure do |config| | |
config.include KujiRspecFixtureLoader | |
end | |
module RSpec | |
module Core | |
class ExampleGroup | |
include KujiRspecFixtureLoader | |
end | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment