#--
# Copyright (c) 2010 Engine Yard, Inc.
# This source code is available under the MIT license.
# See the file LICENSE.txt for details.
#++
require File.dirname(__FILE__) + '/../spec_helper'
describe Warbler::War do
before(:each) do
@rake = Rake::Application.new
Rake.application = @rake
verbose(false)
@pwd = Dir.getwd
Dir.chdir("spec/sample")
mkdir_p "log"
touch "log/test.log"
@config = Warbler::Config.new do |config|
config.war_name = "warbler"
config.gems = ["rake"]
config.webxml.jruby.max.runtimes = 5
end
@war = Warbler::War.new
end
after(:each) do
rm_rf "log"
rm_rf ".bundle"
rm_f FileList["*.war", "config.ru", "*web.xml*", "config/web.xml*",
"config/warble.rb", "file.txt", 'manifest', 'Gemfile*']
Dir.chdir(@pwd)
end
def file_list(regex)
@war.files.keys.select {|f| f =~ regex }
end
it "should collect files in public" do
@war.apply(@config)
file_list(%r{^index\.html}).should_not be_empty
end
it "should collect gem files" do
@config.gems << "rake"
@war.apply(@config)
file_list(%r{WEB-INF/gems/gems/rake.*/lib/rake.rb}).should_not be_empty
file_list(%r{WEB-INF/gems/specifications/rake.*\.gemspec}).should_not be_empty
end
it "should not include log files by default" do
@war.apply(@config)
file_list(%r{WEB-INF/log}).should_not be_empty
file_list(%r{WEB-INF/log/.*\.log}).should be_empty
end
def expand_webxml
@war.apply(@config)
@war.files.should include("WEB-INF/web.xml")
require 'rexml/document'
REXML::Document.new(@war.files["WEB-INF/web.xml"]).root.elements
end
it "should create a web.xml file" do
elements = expand_webxml
elements.to_a(
"context-param/param-name[text()='jruby.max.runtimes']"
).should_not be_empty
elements.to_a(
"context-param/param-name[text()='jruby.max.runtimes']/../param-value"
).first.text.should == "5"
end
it "should include custom context parameters in web.xml" do
@config.webxml.some.custom.config = "myconfig"
elements = expand_webxml
elements.to_a(
"context-param/param-name[text()='some.custom.config']"
).should_not be_empty
elements.to_a(
"context-param/param-name[text()='some.custom.config']/../param-value"
).first.text.should == "myconfig"
end
it "should allow one jndi resource to be included" do
@config.webxml.jndi = 'jndi/rails'
elements = expand_webxml
elements.to_a(
"resource-ref/res-ref-name[text()='jndi/rails']"
).should_not be_empty
end
it "should allow multiple jndi resources to be included" do
@config.webxml.jndi = ['jndi/rails1', 'jndi/rails2']
elements = expand_webxml
elements.to_a(
"resource-ref/res-ref-name[text()='jndi/rails1']"
).should_not be_empty
elements.to_a(
"resource-ref/res-ref-name[text()='jndi/rails2']"
).should_not be_empty
end
it "should not include any ignored context parameters" do
@config.webxml.foo = "bar"
@config.webxml.ignored << "foo"
elements = expand_webxml
elements.to_a(
"context-param/param-name[text()='foo']"
).should be_empty
elements.to_a(
"context-param/param-name[text()='ignored']"
).should be_empty
elements.to_a(
"context-param/param-name[text()='jndi']"
).should be_empty
end
it "should use a config/web.xml if it exists" do
mkdir_p "config"
touch "config/web.xml"
@war.apply(Warbler::Config.new)
@war.files["WEB-INF/web.xml"].should == "config/web.xml"
end
it "should use a config/web.xml.erb if it exists" do
mkdir_p "config"
File.open("config/web.xml.erb", "w") {|f| f << "Hi <%= webxml.public.root %>" }
@war.apply(Warbler::Config.new)
@war.files["WEB-INF/web.xml"].should_not be_nil
@war.files["WEB-INF/web.xml"].read.should == "Hi /"
end
it "should collect java libraries" do
@war.apply(@config)
file_list(%r{WEB-INF/lib/jruby-.*\.jar$}).should_not be_empty
end
it "should collect application files" do
@war.apply(@config)
file_list(%r{WEB-INF/app$}).should_not be_empty
file_list(%r{WEB-INF/config$}).should_not be_empty
file_list(%r{WEB-INF/lib$}).should_not be_empty
end
it "should accept an autodeploy directory where the war should be created" do
require 'tmpdir'
@config.autodeploy_dir = Dir::tmpdir
touch "file.txt"
@war.files["file.txt"] = "file.txt"
silence { @war.create(@config) }
File.exist?(File.join("#{Dir::tmpdir}","warbler.war")).should == true
end
it "should accept a custom manifest file" do
touch 'manifest'
@config.manifest_file = 'manifest'
@war.apply(@config)
@war.files['META-INF/MANIFEST.MF'].should == "manifest"
end
it "should be able to exclude files from the .war" do
@config.excludes += FileList['lib/tasks/utils.rake']
@war.apply(@config)
file_list(%r{lib/tasks/utils.rake}).should be_empty
end
it "should read configuration from #{Warbler::Config::FILE}" do
mkdir_p "config"
File.open(Warbler::Config::FILE, "w") do |dest|
contents =
File.open("#{Warbler::WARBLER_HOME}/warble.rb") do |src|
src.read
end
dest << contents.sub(/# config\.war_name/, 'config.war_name'
).sub(/# config.gems << "tzinfo"/, 'config.gems = []')
end
t = Warbler::Task.new "warble"
t.config.war_name.should == "mywar"
end
it "should fail if a gem is requested that is not installed" do
@config.gems = ["nonexistent-gem"]
lambda {
Warbler::Task.new "warble", @config
@war.apply(@config)
}.should raise_error
end
it "should allow specification of dependency by Gem::Dependency" do
spec = mock "gem spec"
spec.stub!(:full_name).and_return "hpricot-0.6.157"
spec.stub!(:full_gem_path).and_return "hpricot-0.6.157"
spec.stub!(:loaded_from).and_return "hpricot.gemspec"
spec.stub!(:files).and_return ["Rakefile"]
spec.stub!(:dependencies).and_return []
Gem.source_index.should_receive(:search).and_return do |gem|
gem.name.should == "hpricot"
[spec]
end
@config.gems = [Gem::Dependency.new("hpricot", "> 0.6")]
@war.apply(@config)
end
it "should copy loose java classes to WEB-INF/classes" do
@config.java_classes = FileList["Rakefile"]
@war.apply(@config)
file_list(%r{WEB-INF/classes/Rakefile$}).should_not be_empty
end
def mock_rails_module
rails = Module.new
Object.const_set("Rails", rails)
version = Module.new
rails.const_set("VERSION", version)
version.const_set("STRING", "2.1.0")
rails
end
def mock_merb_module
merb = Module.new
silence { Object.const_set("Merb", merb) }
boot_loader = Module.new
merb.const_set("BootLoader", boot_loader)
merb.const_set("VERSION", "1.0")
dependencies = Class.new do
@@dependencies = []
def self.dependencies
@@dependencies
end
def self.dependencies=(deps)
@@dependencies = deps
end
end
boot_loader.const_set("Dependencies", dependencies)
dependencies
end
it "should auto-detect a Rails application" do
task :environment do
mock_rails_module
end
@config = Warbler::Config.new
@config.webxml.booter.should == :rails
@config.gems["rails"].should == "2.1.0"
end
it "should provide Rails gems by default, unless vendor/rails is present" do
rails = nil
task :environment do
rails = mock_rails_module
end
config = Warbler::Config.new
config.gems.should have_key("rails")
mkdir_p "vendor/rails"
config = Warbler::Config.new
config.gems.should be_empty
rm_rf "vendor/rails"
rails.stub!(:vendor_rails?).and_return true
config = Warbler::Config.new
config.gems.should be_empty
end
it "should not try to autodetect frameworks when Warbler.framework_detection is false" do
begin
Warbler.framework_detection = false
task :environment
config = Warbler::Config.new
config.webxml.booter.should_not == :rails
t = Rake::Task['environment']
class << t; public :instance_variable_get; end
t.instance_variable_get("@already_invoked").should == false
ensure
Warbler.framework_detection = true
end
end
it "should auto-detect a Merb application" do
task :merb_env do
mock_merb_module
end
@config = Warbler::Config.new
@config.webxml.booter.should == :merb
@config.gems.keys.should_not include("rails")
end
it "should auto-detect a Rack application with a config.ru file" do
rackup = "run Proc.new {|env| [200, {}, ['Hello World']]}"
File.open("config.ru", "w") {|f| f << rackup }
@config = Warbler::Config.new
@config.webxml.booter.should == :rack
@config.webxml.rackup.should == rackup
end
it "should automatically add Rails.configuration.gems to the list of gems" do
task :environment do
rails = mock_rails_module
config = mock "config"
rails.stub!(:configuration).and_return(config)
gem = mock "gem"
gem.stub!(:name).and_return "hpricot"
gem.stub!(:requirement).and_return Gem::Requirement.new("=0.6")
config.stub!(:gems).and_return [gem]
end
@config = Warbler::Config.new
@config.webxml.booter.should == :rails
@config.gems.keys.should include(Gem::Dependency.new("hpricot", Gem::Requirement.new("=0.6")))
end
it "should automatically add Merb::BootLoader::Dependencies.dependencies to the list of gems" do
task :merb_env do
deps = mock_merb_module
deps.dependencies = [Gem::Dependency.new("merb-core", ">= 1.0.6.1")]
end
@config = Warbler::Config.new
@config.webxml.booter.should == :merb
@config.gems.keys.should include(Gem::Dependency.new("merb-core", ">= 1.0.6.1"))
end
it "should skip Merb development dependencies" do
task :merb_env do
deps = mock_merb_module
deps.dependencies = [Gem::Dependency.new("rake", "= #{RAKEVERSION}", :development)]
end
@war.apply(Warbler::Config.new)
file_list(/rake-#{RAKEVERSION}/).should be_empty
end
it "should warn about using Merb < 1.0" do
task :merb_env do
silence { Object.const_set("Merb", Module.new) }
end
@config = silence { Warbler::Config.new }
@config.webxml.booter.should == :merb
end
it "should set the jruby max runtimes to 1 when MT Rails is detected" do
task :environment do
rails = mock_rails_module
config = mock "config"
rails.stub!(:configuration).and_return(config)
config.stub!(:threadsafe!)
config.should_receive(:allow_concurrency).and_return true
config.should_receive(:preload_frameworks).and_return true
end
@config = Warbler::Config.new
@config.webxml.booter.should == :rails
@config.webxml.jruby.max.runtimes.should == 1
end
it "should skip directories that don't exist in config.dirs and print a warning" do
@config.dirs = %w(lib notexist)
silence { @war.apply(@config) }
file_list(%r{WEB-INF/lib}).should_not be_empty
file_list(%r{WEB-INF/notexist}).should be_empty
end
it "should write gems to location specified by gem_path" do
@config = Warbler::Config.new {|c| c.gem_path = "/WEB-INF/jewels"; c.gems << 'rake' }
elements = expand_webxml
file_list(%r{WEB-INF/jewels}).should_not be_empty
elements.to_a(
"context-param/param-name[text()='gem.path']"
).should_not be_empty
elements.to_a(
"context-param/param-name[text()='gem.path']/../param-value"
).first.text.should == "/WEB-INF/jewels"
end
it "should detect a Bundler Gemfile and process only its gems" do
File.open("Gemfile", "w") {|f| f << "gem 'rspec'"}
@war.apply(Warbler::Config.new {|c| c.gems << "rake"})
file_list(%r{WEB-INF/Gemfile}).should_not be_empty
file_list(%r{WEB-INF/gems/specifications/rspec}).should_not be_empty
file_list(%r{WEB-INF/gems/specifications/rake}).should be_empty
end
it "should write a Bundler environment file into the war" do
File.open("Gemfile", "w") {|f| f << "gem 'rspec'"}
@war.apply(Warbler::Config.new)
file_list(%r{WEB-INF/\.bundle/environment\.rb}).should_not be_empty
end
it "should allow overriding of the gem path when using Bundler" do
File.open("Gemfile", "w") {|f| f << "gem 'rspec'"}
@war.apply(Warbler::Config.new {|c| c.gem_path = '/WEB-INF/jewels' })
file_list(%r{WEB-INF/jewels/specifications/rspec}).should_not be_empty
IO.readlines(".bundle/war-environment.rb").grep(/rspec/).last.should =~ %r{jewels/specifications}m
end
it "should not let the framework load Bundler from the locked environment" do
task :environment do
File.exist?('.bundle/environment.rb').should_not be_true
mock_rails_module
end
File.open("Gemfile", "w") {|f| f << "gem 'rspec'"}
`ruby -S bundle lock`
File.exist?('.bundle/environment.rb').should be_true
@war.apply(Warbler::Config.new)
hash = eval("[" + IO.readlines(".bundle/environment.rb").grep(/rspec/).last + "]").first
hash[:load_paths].each {|p| File.exist?(p).should be_true }
end
it "should allow adding additional WEB-INF files via config.webinf_files" do
File.open("myserver-web.xml", "w") do |f|
f << ""
end
@war.apply(Warbler::Config.new {|c| c.webinf_files = FileList['myserver-web.xml'] })
file_list(%r{WEB-INF/myserver-web.xml}).should_not be_empty
end
it "should allow expanding of additional WEB-INF files via config.webinf_files" do
File.open("myserver-web.xml.erb", "w") do |f|
f << "<%= webxml.rails.env %>"
end
@war.apply(Warbler::Config.new {|c| c.webinf_files = FileList['myserver-web.xml.erb'] })
file_list(%r{WEB-INF/myserver-web.xml}).should_not be_empty
@war.files['WEB-INF/myserver-web.xml'].read.should =~ /web-app.*production/
end
end