initial fun commit

This commit is contained in:
John Bintz 2012-02-01 10:06:30 -05:00
commit 3325bce18b
11 changed files with 290 additions and 0 deletions

17
.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
*.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp

4
Gemfile Normal file
View File

@ -0,0 +1,4 @@
source 'https://rubygems.org'
# Specify your gem's dependencies in vegetable_glue.gemspec
gemspec

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
Copyright (c) 2012 John Bintz
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

54
README.md Normal file
View File

@ -0,0 +1,54 @@
# VegetableGlue
Easy way to start/stop/restart a dependent Rails API app in a consumer's acceptance tests.
Uses `database_cleaner`'s `:truncation` mode to clean out your databases after each run.
## Installation & Usage
In both apps' Gemfiles:
``` ruby
gem 'vegetable_glue'
```
In the provider (API):
* Create or use a Rails environment that has a database that you don't mind nuking (say `test`, `acceptance`, or `cucumber`)
* Modify `config/routes.rb`:
``` ruby
require 'vegetable_glue/routes'
MyApp::Application.routes.draw do
# ... your other routes ...
acceptance_helper_routes #=> for the :acceptance env, or
acceptance_helper_routes_for :cucumber #=> for the :cucumber env
end
The two additional routes are only added in that environment.
In the consumer (Frontend):
* For Cucumber, add the following to `features/support/env.rb`:
``` ruby
require 'vegetable_glue/cucumber'
VegetableGlue.url = 'http://localhost:6161/' #=> include the port in here, too, that's where the app will run
VegetableGlue.path = '../path/to/the/app'
```
The app will clean its database on each scenario. To restart the app, pass in the environment variable `GLUE_RESTART`:
GLUE_RESTART=true bundle exec cucumber
If you're using ActiveResource, a good source of the URL is `ActiveResource::Base.site`.
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request

2
Rakefile Normal file
View File

@ -0,0 +1,2 @@
#!/usr/bin/env rake
require "bundler/gem_tasks"

33
lib/vegetable_glue.rb Normal file
View File

@ -0,0 +1,33 @@
require "vegetable_glue/version"
require 'net/http'
require 'fileutils'
module VegetableGlue
autoload :Runner, 'vegetable_glue/runner'
ACCEPTANCE = '__acceptance__'
CLEAN = '__clean__'
class << self
attr_accessor :url, :path, :env
def shutdown
Runner.new(options).shutdown
end
def clean
Runner.new(options).clean
end
def env
@env ||= :cucumber
end
private
def options
{ :url => url, :path => path, :env => env }
end
end
end

View File

@ -0,0 +1,11 @@
Before do
if ENV['GLUE_RESTART']
VegetableGlue.shutdown
ENV.delete('GLUE_RESTART')
end
VegetableGlue.clean
end

View File

@ -0,0 +1,20 @@
class ActionDispatch::Routing::Mapper
def acceptance_helper_routes
acceptance_helper_routes_for
end
def acceptance_helper_routes_for(env = :acceptance)
if Rails.env.to_sym == env
get VegetableGlue::ACCEPTANCE => lambda { |env| [ 200, {}, [ VegetableGlue::ACCEPTANCE ] ] }
get VegetableGlue::CLEAN => lambda { |env|
require 'database_cleaner'
DatabaseCleaner.clean_with :truncation
[ 200, {}, [ VegetableGlue::CLEAN ] ]
}
end
end
end

View File

@ -0,0 +1,105 @@
module VegetableGlue
class Runner
attr_reader :options
def initialize(options = {})
@options = options
end
def ensure_running
port = options[:url].port
result = nil
begin
result = get_acceptance
rescue Errno::ECONNREFUSED => e
$stdout.puts "Starting #{app_name}..."
Bundler.with_clean_env do
system %{cd #{options[:path]} && bundle exec rails server -p #{port} -d -e #{options[:env]} -P #{pid_path}}
end
raise StandardError.new("#{app_name} did not start up in 30 seconds!") if !(result = wait_for_up)
end
if result == VegetableGlue::ACCEPTANCE
$stdout.puts "#{app_name} running on port #{port}"
else
raise StandardError.new("Is #{app_name} running? You should have included the routes with `acceptance_helper_routes`")
end
end
def shutdown
if File.file?(pid_path)
system %{kill -INT #{File.read(pid_path)}}
wait_for_down
$stdout.puts "#{app_name} shut down"
end
FileUtils.rm_f pid_path
end
def clean
ensure_running
result = Net::HTTP.get(options[:url].merge(URI("/#{VegetableGlue::CLEAN}")))
raise StandardError.new("#{app_name} database not cleaned") if result != VegetableGlue::CLEAN
end
def pid_path
File.join(File.expand_path(options[:path]), "tmp/pids/#{options[:env]}.pid")
end
private
def get_acceptance
Net::HTTP.get(options[:url].merge(URI("/#{VegetableGlue::ACCEPTANCE}")))
end
def app_name
File.basename(options[:path])
end
def wait_for_down
times = 30
while times > 0
begin
Net::HTTP.get(options[:url])
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
return true
end
times -= 1
sleep 1
end
raise StandardError.new("#{app_name} did not shut down")
end
def wait_for_up
times = 30
result = nil
while times > 0
begin
result = get_acceptance
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
end
break if result
sleep 1
times -= 1
end
result
end
end
end

View File

@ -0,0 +1,3 @@
module VegetableGlue
VERSION = "0.0.1"
end

19
vegetable_glue.gemspec Normal file
View File

@ -0,0 +1,19 @@
# -*- encoding: utf-8 -*-
require File.expand_path('../lib/vegetable_glue/version', __FILE__)
Gem::Specification.new do |gem|
gem.authors = ["John Bintz"]
gem.email = ["john@coswellproductions.com"]
gem.description = %q{TODO: Write a gem description}
gem.summary = %q{TODO: Write a gem summary}
gem.homepage = ""
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
gem.files = `git ls-files`.split("\n")
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
gem.name = "vegetable_glue"
gem.require_paths = ["lib"]
gem.version = VegetableGlue::VERSION
gem.add_dependency 'database_cleaner'
end