describe ConfigScripts::Scripts::Script do let(:klass) { ConfigScripts::Scripts::Script } describe "class methods" do describe "script_directory" do subject { klass.script_directory} it "is the db/config_scripts directory" do expect(subject).to eq Rails.root.join('db', 'config_scripts') end end describe "pending_scripts" do let!(:filename1) { "20140208150000_script_1" } let!(:filename2) { "20140208200000_script_2" } subject { klass.pending_scripts } before do Dir.stub glob: ["/tmp/#{filename1}.rb", "/tmp/#{filename2}.rb"] ConfigScripts::Scripts::ScriptHistory.record_timestamp('20140208150000') end it "uses Dir to get the files" do subject expect(Dir).to have_received(:glob).with(File.join(klass.script_directory, "*.rb")) end it "includes filenames that don't have entries in the script histories" do expect(subject).to include filename2 end it "does not include filenames that have entries in the script history" do expect(subject).not_to include filename1 end end describe "run_pending_scripts" do class TestConfigScriptConfig < ConfigScripts::Scripts::Script; end let(:script_filenames) { [double, double, double] } before do klass.stub pending_scripts: script_filenames klass.stub :run_file end context "with no problems running the scripts" do before do klass.run_pending_scripts end it "runs the scripts" do expect(klass).to have_received(:run_file).with(script_filenames[0]) expect(klass).to have_received(:run_file).with(script_filenames[1]) expect(klass).to have_received(:run_file).with(script_filenames[2]) end end context "with a problems running the scripts" do before do klass.stub(:run_file).with(script_filenames[1]).and_raise end it "raises an exception" do expect(lambda{klass.run_pending_scripts}).to raise_exception end it "stops running the scripts when it hits the exception" do klass.run_pending_scripts rescue nil expect(klass).to have_received(:run_file).with(script_filenames[0]) expect(klass).to have_received(:run_file).with(script_filenames[1]) expect(klass).not_to have_received(:run_file).with(script_filenames[2]) end end end describe "run_file" do class TestConfigScriptConfig < ConfigScripts::Scripts::Script; end let(:timestamp) { '20140208150000' } let(:filename) { "#{timestamp}_test_config_script" } let!(:script) { TestConfigScriptConfig.new(timestamp) } let(:path) { Rails.root.join("db", "config_scripts", "#{filename}.rb") } before do script.stub :run TestConfigScriptConfig.stub new: script klass.stub :require klass.stub :puts end context "with no problems running the scripts" do before do klass.run_file(filename, :sideways) end it "requires the file" do expect(klass).to have_received(:require).with(path) end it "puts the name of the file out to the console" do expect(klass).to have_received(:puts).with("Running #{filename} sideways") end it "creates a config script with the class and timestamp" do expect(TestConfigScriptConfig).to have_received(:new).with(timestamp) end it "calls the run command on the script with the direction" do expect(script).to have_received(:run).with(:sideways) end end context "with a problem running the script" do before do script.stub(:run).and_raise 'error' end it "re-raises the exception" do expect(lambda{klass.run_file(filename)}).to raise_exception 'error' end end context "with a problem finding the class" do it "re-raises the exception" do expect(lambda{klass.run_file("#{timestamp}_test_config_script_2")}).to raise_exception NameError end end end describe "filename_for_script" do let(:name) { 'my_change' } let(:path) { File.join(klass.script_directory, "*#{name}.rb") } let(:filename) { "1234512345_#{name}" } subject { klass.filename_for_script(name) } context "when there are multiple files that have the name" do before do Dir.stub(:glob).with(path).and_return(["#{filename}.rb", "5123451234_#{name}.rb"]) end it "is the first one" do expect(subject).to eq filename end end context "when there is one file with the exact name, and one that just ends with the name" do before do Dir.stub(:glob).with(path).and_return(["5123451234_prepare_#{name}.rb", "#{filename}.rb"]) end it "is the one with the exact name" do expect(subject).to eq filename end end context "when there are no files with the name" do before do Dir.stub(:glob).with(path).and_return([]) end it "is nil" do expect(subject).to be_nil end end end describe "list_pending_scripts" do before do klass.stub pending_scripts: ['script1.rb', 'script2.rb'] klass.stub :puts klass.list_pending_scripts end it "prints out the name of each script" do expect(klass).to have_received(:puts).with('script1.rb') expect(klass).to have_received(:puts).with('script2.rb') end end end describe "creating" do let(:timestamp) { '20140101153500' } subject { klass.new(timestamp) } it "sets the timestamp" do expect(subject.timestamp).to eq timestamp end end describe "running" do let(:timestamp) { 1.day.ago.to_s(:number)} let(:script) { ConfigScripts::Scripts::Script.new(timestamp) } describe "up" do it "raises an exception" do expect(lambda{script.up}).to raise_exception("Not supported") end end describe "down" do it "raises an exception" do expect(lambda{script.down}).to raise_exception("Not supported") end end describe "run" do {up: true, down: false}.each do |direction, expect_timestamp| describe "direction" do before do if !expect_timestamp ConfigScripts::Scripts::ScriptHistory.record_timestamp(timestamp) end script.stub :puts Rails.cache.write("cached_item", "cached_value") end context "with a success" do before do script.stub(direction) do Person.create(name: 'John Doe') end script.run(direction) end it "performs the changes in the #{direction} method" do expect(Person.count).to eq 1 expect(Person.first.name).to eq "John Doe" end it "cleares the cache" do expect(Rails.cache.read("cached_item")).to be_nil end it "{expect_timestamp ? 'adds' : 'removes'} the timestamp" do expect(ConfigScripts::Scripts::ScriptHistory.script_was_run?(timestamp)).to eq expect_timestamp end end context "with an exception in the #{direction} method" do before do script.stub(direction) do Person.create(name: 'John Doe') raise end end it "re-raises the exception" do expect(lambda{script.run(direction)}).to raise_exception end it "does not persist the changes in the #{direction} method" do script.run(direction) rescue nil expect(Person.count).to eq 0 end it "does not clear the cache" do script.run(direction) rescue nil expect(Rails.cache.read('cached_item')).to eq 'cached_value' end it "does not #{expect_timestamp ? 'add' : 'remove'} the timestamp" do script.run(direction) rescue nil expect(ConfigScripts::Scripts::ScriptHistory.script_was_run?(timestamp)).not_to eq expect_timestamp end it "puts an error out to the logs" do script.run(direction) rescue nil expect(script).to have_received(:puts).with("Error running script for ConfigScripts::Scripts::Script: ") end end end end end end end