Browse files

Add standalone framework

- Add new standalone framework

- Allow users to choose runtime from
list if framework is standalone

- Allow default runtime to be specified
by framework

- Pass start command to server
on app creation

- Allow default memory to be specified by
runtime/framework combo

- Support pushing a single file, including
unpack and repack of zip and WAR

- Allow "None" as URL choice for standalone
apps

Change-Id: Icdc1ae9098a9365e3ec26b3bf2e5f215437a56a1
  • Loading branch information...
1 parent b627c98 commit df63c0927a50f92695f5aa2556b885c64c6d4f0f Jennifer Hickey committed Mar 13, 2012
View
2 Rakefile
@@ -30,6 +30,8 @@ TESTS_TO_BUILD = ["#{TESTS_PATH}/java_web/java_tiny_app",
"#{TESTS_PATH}/lift/hello_lift",
"#{TESTS_PATH}/spring/roo-guestbook",
"#{TESTS_PATH}/spring/spring-osgi-hello",
+ "#{TESTS_PATH}/standalone/java_app",
+ "#{TESTS_PATH}/standalone/python_app"
]
desc "Build the tests. If the git hash associated with the test assets has not changed, nothing is built. To force a build, invoke 'rake build[--force]'"
View
217 lib/cli/commands/apps.rb
@@ -371,7 +371,6 @@ def app_exists?(appname)
def check_deploy_directory(path)
err 'Deployment path does not exist' unless File.exists? path
- err 'Deployment path is not a directory' unless File.directory? path
return if File.expand_path(Dir.tmpdir) != File.expand_path(path)
err "Can't deploy applications from staging directory: [#{Dir.tmpdir}]"
end
@@ -410,101 +409,112 @@ def upload_app_bits(appname, path)
explode_dir = "#{Dir.tmpdir}/.vmc_#{appname}_files"
FileUtils.rm_rf(explode_dir) # Make sure we didn't have anything left over..
- Dir.chdir(path) do
- # Stage the app appropriately and do the appropriate fingerprinting, etc.
- if war_file = Dir.glob('*.war').first
- VMC::Cli::ZipUtil.unpack(war_file, explode_dir)
- else
- check_unreachable_links(path)
- FileUtils.mkdir(explode_dir)
+ if path =~ /\.(war|zip)$/
+ #single file that needs unpacking
+ VMC::Cli::ZipUtil.unpack(path, explode_dir)
+ elsif !File.directory? path
+ #single file that doesn't need unpacking
+ FileUtils.mkdir(explode_dir)
+ FileUtils.cp(path,explode_dir)
+ else
+ Dir.chdir(path) do
+ # Stage the app appropriately and do the appropriate fingerprinting, etc.
+ if war_file = Dir.glob('*.war').first
+ VMC::Cli::ZipUtil.unpack(war_file, explode_dir)
+ elsif zip_file = Dir.glob('*.zip').first
+ VMC::Cli::ZipUtil.unpack(zip_file, explode_dir)
+ else
+ check_unreachable_links(path)
+ FileUtils.mkdir(explode_dir)
- files = Dir.glob('{*,.[^\.]*}')
+ files = Dir.glob('{*,.[^\.]*}')
- # Do not process .git files
- files.delete('.git') if files
+ # Do not process .git files
+ files.delete('.git') if files
- FileUtils.cp_r(files, explode_dir)
+ FileUtils.cp_r(files, explode_dir)
- find_sockets(explode_dir).each do |s|
- File.delete s
+ find_sockets(explode_dir).each do |s|
+ File.delete s
+ end
end
end
+ end
- # Send the resource list to the cloudcontroller, the response will tell us what it already has..
- unless @options[:noresources]
- display ' Checking for available resources: ', false
- fingerprints = []
- total_size = 0
- resource_files = Dir.glob("#{explode_dir}/**/*", File::FNM_DOTMATCH)
- resource_files.each do |filename|
- next if (File.directory?(filename) || !File.exists?(filename))
- fingerprints << {
- :size => File.size(filename),
- :sha1 => Digest::SHA1.file(filename).hexdigest,
- :fn => filename
- }
- total_size += File.size(filename)
- end
-
- # Check to see if the resource check is worth the round trip
- if (total_size > (64*1024)) # 64k for now
- # Send resource fingerprints to the cloud controller
- appcloud_resources = client.check_resources(fingerprints)
- end
- display 'OK'.green
-
- if appcloud_resources
- display ' Processing resources: ', false
- # We can then delete what we do not need to send.
- appcloud_resources.each do |resource|
- FileUtils.rm_f resource[:fn]
- # adjust filenames sans the explode_dir prefix
- resource[:fn].sub!("#{explode_dir}/", '')
- end
- display 'OK'.green
- end
+ # Send the resource list to the cloudcontroller, the response will tell us what it already has..
+ unless @options[:noresources]
+ display ' Checking for available resources: ', false
+ fingerprints = []
+ total_size = 0
+ resource_files = Dir.glob("#{explode_dir}/**/*", File::FNM_DOTMATCH)
+ resource_files.each do |filename|
+ next if (File.directory?(filename) || !File.exists?(filename))
+ fingerprints << {
+ :size => File.size(filename),
+ :sha1 => Digest::SHA1.file(filename).hexdigest,
+ :fn => filename
+ }
+ total_size += File.size(filename)
+ end
+ # Check to see if the resource check is worth the round trip
+ if (total_size > (64*1024)) # 64k for now
+ # Send resource fingerprints to the cloud controller
+ appcloud_resources = client.check_resources(fingerprints)
end
+ display 'OK'.green
- # If no resource needs to be sent, add an empty file to ensure we have
- # a multi-part request that is expected by nginx fronting the CC.
- if VMC::Cli::ZipUtil.get_files_to_pack(explode_dir).empty?
- Dir.chdir(explode_dir) do
- File.new(".__empty__", "w")
+ if appcloud_resources
+ display ' Processing resources: ', false
+ # We can then delete what we do not need to send.
+ appcloud_resources.each do |resource|
+ FileUtils.rm_f resource[:fn]
+ # adjust filenames sans the explode_dir prefix
+ resource[:fn].sub!("#{explode_dir}/", '')
end
+ display 'OK'.green
end
- # Perform Packing of the upload bits here.
- display ' Packing application: ', false
- VMC::Cli::ZipUtil.pack(explode_dir, upload_file)
- display 'OK'.green
- upload_size = File.size(upload_file);
- if upload_size > 1024*1024
- upload_size = (upload_size/(1024.0*1024.0)).round.to_s + 'M'
- elsif upload_size > 0
- upload_size = (upload_size/1024.0).round.to_s + 'K'
- else
- upload_size = '0K'
+ end
+
+ # If no resource needs to be sent, add an empty file to ensure we have
+ # a multi-part request that is expected by nginx fronting the CC.
+ if VMC::Cli::ZipUtil.get_files_to_pack(explode_dir).empty?
+ Dir.chdir(explode_dir) do
+ File.new(".__empty__", "w")
end
+ end
+ # Perform Packing of the upload bits here.
+ display ' Packing application: ', false
+ VMC::Cli::ZipUtil.pack(explode_dir, upload_file)
+ display 'OK'.green
- upload_str = " Uploading (#{upload_size}): "
- display upload_str, false
+ upload_size = File.size(upload_file);
+ if upload_size > 1024*1024
+ upload_size = (upload_size/(1024.0*1024.0)).round.to_s + 'M'
+ elsif upload_size > 0
+ upload_size = (upload_size/1024.0).round.to_s + 'K'
+ else
+ upload_size = '0K'
+ end
- FileWithPercentOutput.display_str = upload_str
- FileWithPercentOutput.upload_size = File.size(upload_file);
- file = FileWithPercentOutput.open(upload_file, 'rb')
+ upload_str = " Uploading (#{upload_size}): "
+ display upload_str, false
- client.upload_app(appname, file, appcloud_resources)
- display 'OK'.green if VMC::Cli::ZipUtil.get_files_to_pack(explode_dir).empty?
+ FileWithPercentOutput.display_str = upload_str
+ FileWithPercentOutput.upload_size = File.size(upload_file);
+ file = FileWithPercentOutput.open(upload_file, 'rb')
- display 'Push Status: ', false
- display 'OK'.green
- end
+ client.upload_app(appname, file, appcloud_resources)
+ display 'OK'.green if VMC::Cli::ZipUtil.get_files_to_pack(explode_dir).empty?
- ensure
- # Cleanup if we created an exploded directory.
- FileUtils.rm_f(upload_file) if upload_file
- FileUtils.rm_rf(explode_dir) if explode_dir
+ display 'Push Status: ', false
+ display 'OK'.green
+
+ ensure
+ # Cleanup if we created an exploded directory.
+ FileUtils.rm_f(upload_file) if upload_file
+ FileUtils.rm_rf(explode_dir) if explode_dir
end
def check_app_limit
@@ -908,6 +918,8 @@ def do_push(appname=nil)
url = info(:url) || info(:urls)
mem, memswitch = nil, info(:mem)
memswitch = normalize_mem(memswitch) if memswitch
+ command = info(:command)
+ runtime = info(:runtime)
# Check app existing upfront if we have appname
app_checked = false
@@ -934,9 +946,30 @@ def do_push(appname=nil)
err "Application '#{appname}' already exists, use update or delete."
end
- default_url = "#{appname}.#{target_base}"
+ if ignore_framework
+ framework = VMC::Cli::Framework.new
+ elsif f = info(:framework)
+ info = Hash[f["info"].collect { |k, v| [k.to_sym, v] }]
+
+ framework = VMC::Cli::Framework.create(f["name"], info)
+ exec = framework.exec if framework && framework.exec
+ else
+ framework = detect_framework(prompt_ok)
+ end
+
+ err "Application Type undetermined for path '#{@application}'" unless framework
+
+ if not runtime
+ default_runtime = framework.default_runtime @application
+ runtime = detect_runtime(default_runtime, !no_prompt) if framework.prompt_for_runtime?
+ end
+ command = ask("Start Command") if !command && framework.require_start_command?
+
+ default_url = "None"
+ default_url = "#{appname}.#{VMC::Cli::Config.suggest_url}" if framework.require_url?
+
- unless no_prompt || url
+ unless no_prompt || url || !framework.require_url?
url = ask(
"Application Deployed URL",
:default => default_url
@@ -947,29 +980,18 @@ def do_push(appname=nil)
# this common error
url = nil if YES_SET.member? url
end
-
+ url = nil if url == "None"
+ default_url = nil if default_url == "None"
url ||= default_url
- if ignore_framework
- framework = VMC::Cli::Framework.new
- elsif f = info(:framework)
- info = Hash[f["info"].collect { |k, v| [k.to_sym, v] }]
-
- framework = VMC::Cli::Framework.new(f["name"], info)
- exec = framework.exec if framework && framework.exec
- else
- framework = detect_framework(prompt_ok)
- end
-
- err "Application Type undetermined for path '#{@application}'" unless framework
-
if memswitch
mem = memswitch
elsif prompt_ok
mem = ask("Memory Reservation",
- :default => framework.memory, :choices => mem_choices)
+ :default => framework.memory(runtime),
+ :choices => mem_choices)
else
- mem = framework.memory
+ mem = framework.memory runtime
end
# Set to MB number
@@ -984,14 +1006,15 @@ def do_push(appname=nil)
:name => "#{appname}",
:staging => {
:framework => framework.name,
- :runtime => info(:runtime)
+ :runtime => runtime
},
:uris => Array(url),
:instances => instances,
:resources => {
:memory => mem_quota
- },
+ }
}
+ manifest[:staging][:command] = command if command
# Send the manifest to the cloud controller
client.create_app(appname, manifest)
View
159 lib/cli/frameworks.rb
@@ -11,6 +11,7 @@ class Framework
'Grails' => ['grails', { :mem => '512M', :description => 'Java SpringSource Grails Application'}],
'Lift' => ['lift', { :mem => '512M', :description => 'Scala Lift Application'}],
'JavaWeb' => ['java_web',{ :mem => '512M', :description => 'Java Web Application'}],
+ 'Standalone' => ['standalone', { :mem => '64M', :description => 'Standalone Application'}],
'Sinatra' => ['sinatra', { :mem => '128M', :description => 'Sinatra Application'}],
'Node' => ['node', { :mem => '64M', :description => 'Node.js Application'}],
'PHP' => ['php', { :mem => '128M', :description => 'PHP Application'}],
@@ -27,16 +28,33 @@ def known_frameworks
end
def lookup(name)
- return Framework.new(*FRAMEWORKS[name])
+ return create(*FRAMEWORKS[name])
end
def lookup_by_framework(name)
FRAMEWORKS.each do |key,fw|
- return Framework.new(fw[0], fw[1]) if fw[0] == name
+ return create(fw[0],fw[1]) if fw[0] == name
+ end
+ end
+
+ def create(name,opts)
+ if name == "standalone"
+ return StandaloneFramework.new(name, opts)
+ else
+ return Framework.new(name,opts)
end
end
def detect(path, available_frameworks)
+ if !File.directory? path
+ if path.end_with?('.war')
+ return detect_framework_from_war path
+ elsif available_frameworks.include?(["standalone"])
+ return Framework.lookup('Standalone')
+ else
+ return nil
+ end
+ end
Dir.chdir(path) do
# Rails
if File.exist?('config/environment.rb')
@@ -46,30 +64,13 @@ def detect(path, available_frameworks)
elsif File.exist?('config.ru') && available_frameworks.include?(["rack"])
return Framework.lookup('Rack')
- # Java
- elsif Dir.glob('*.war').first || File.exist?('WEB-INF/web.xml')
- war_file = Dir.glob('*.war').first
+ # Java Web Apps
+ elsif Dir.glob('*.war').first
+ return detect_framework_from_war(Dir.glob('*.war').first)
- if war_file
- contents = ZipUtil.entry_lines(war_file)
- else
- contents = Dir['**/*'].join("\n")
- end
+ elsif File.exist?('WEB-INF/web.xml')
+ return detect_framework_from_war
- # Spring/Lift Variations
- if contents =~ /WEB-INF\/lib\/grails-web.*\.jar/
- return Framework.lookup('Grails')
- elsif contents =~ /WEB-INF\/lib\/lift-webkit.*\.jar/
- return Framework.lookup('Lift')
- elsif contents =~ /WEB-INF\/classes\/org\/springframework/
- return Framework.lookup('Spring')
- elsif contents =~ /WEB-INF\/lib\/spring-core.*\.jar/
- return Framework.lookup('Spring')
- elsif contents =~ /WEB-INF\/lib\/org\.springframework\.core.*\.jar/
- return Framework.lookup('Spring')
- else
- return Framework.lookup('JavaWeb')
- end
# Simple Ruby Apps
elsif !Dir.glob('*.rb').empty?
matched_file = nil
@@ -81,17 +82,16 @@ def detect(path, available_frameworks)
end
end
if matched_file
+ # Sinatra apps
f = Framework.lookup('Sinatra')
f.exec = "ruby #{matched_file}"
return f
end
-
# Node.js
elsif !Dir.glob('*.js').empty?
if File.exist?('server.js') || File.exist?('app.js') || File.exist?('index.js') || File.exist?('main.js')
return Framework.lookup('Node')
end
-
# PHP
elsif !Dir.glob('*.php').empty?
return Framework.lookup('PHP')
@@ -108,19 +108,42 @@ def detect(path, available_frameworks)
# Python
elsif !Dir.glob('wsgi.py').empty?
return Framework.lookup('WSGI')
-
end
+
+ # Default to Standalone if no other match was made
+ return Framework.lookup('Standalone') if available_frameworks.include?(["standalone"])
end
- nil
end
+ private
+ def detect_framework_from_war(war_file=nil)
+ if war_file
+ contents = ZipUtil.entry_lines(war_file)
+ else
+ #assume we are working with current dir
+ contents = Dir['**/*'].join("\n")
+ end
+
+ # Spring/Lift Variations
+ if contents =~ /WEB-INF\/lib\/grails-web.*\.jar/
+ return Framework.lookup('Grails')
+ elsif contents =~ /WEB-INF\/lib\/lift-webkit.*\.jar/
+ return Framework.lookup('Lift')
+ elsif contents =~ /WEB-INF\/classes\/org\/springframework/
+ return Framework.lookup('Spring')
+ elsif contents =~ /WEB-INF\/lib\/spring-core.*\.jar/
+ return Framework.lookup('Spring')
+ elsif contents =~ /WEB-INF\/lib\/org\.springframework\.core.*\.jar/
+ return Framework.lookup('Spring')
+ else
+ return Framework.lookup('JavaWeb')
+ end
+ end
end
- attr_reader :name, :description, :memory, :console
+ attr_reader :name, :description, :console
attr_accessor :exec
- alias :mem :memory
-
def initialize(framework=nil, opts={})
@name = framework || DEFAULT_FRAMEWORK
@memory = opts[:mem] || DEFAULT_MEM
@@ -132,6 +155,80 @@ def initialize(framework=nil, opts={})
def to_s
description
end
+
+ def require_url?
+ true
+ end
+
+ def require_start_command?
+ false
+ end
+
+ def prompt_for_runtime?
+ false
+ end
+
+ def default_runtime(path)
+ nil
+ end
+
+ def memory(runtime=nil)
+ @memory
+ end
+
+ alias :mem :memory
+ end
+
+ class StandaloneFramework < Framework
+ def require_url?
+ false
+ end
+
+ def require_start_command?
+ true
+ end
+
+ def prompt_for_runtime?
+ true
+ end
+
+ def default_runtime(path)
+ if !File.directory? path
+ if path =~ /\.(jar|class)$/
+ return "java"
+ elsif path =~ /\.(rb)$/
+ return "ruby18"
+ elsif path =~ /\.(zip)$/
+ return detect_runtime_from_zip path
+ end
+ else
+ Dir.chdir(path) do
+ return "ruby18" if not Dir.glob('**/*.rb').empty?
+ if !Dir.glob('**/*.class').empty? || !Dir.glob('**/*.jar').empty?
+ return "java"
+ elsif Dir.glob('*.zip').first
+ zip_file = Dir.glob('*.zip').first
+ return detect_runtime_from_zip zip_file
+ end
+ end
+ end
+ return nil
+ end
+
+ def memory(runtime=nil)
+ default_mem = @memory
+ default_mem = '128M' if runtime =~ /\Aruby/ || runtime == "php"
+ default_mem = '512M' if runtime == "java"
+ default_mem
+ end
+
+ private
+ def detect_runtime_from_zip(zip_file)
+ contents = ZipUtil.entry_lines(zip_file)
+ if contents =~ /\.(jar)$/
+ return "java"
+ end
+ end
end
end
View
72 lib/cli/manifest_helper.rb
@@ -82,22 +82,11 @@ def configure_app(many=false)
name = manifest("name") ||
set(ask("Application Name", :default => manifest("name")), "name")
- url_template = manifest("url") || DEFAULTS["url"]
- url_resolved = url_template.dup
- resolve_lexically(url_resolved)
-
- url = ask("Application Deployed URL", :default => url_resolved)
-
- url = url_template if url == url_resolved
-
- # common error case is for prompted users to answer y or Y or yes or
- # YES to this ask() resulting in an unintended URL of y. Special
- # case this common error
- url = DEFAULTS["url"] if YES_SET.member? url
- set url, "url"
- unless manifest "framework"
+ if manifest "framework"
+ framework = VMC::Cli::Framework.lookup_by_framework manifest("framework","name")
+ else
framework = detect_framework
set framework.name, "framework", "name"
set(
@@ -110,11 +99,44 @@ def configure_app(many=false)
)
end
+ default_runtime = manifest "runtime"
+ if not default_runtime
+ default_runtime = framework.default_runtime(@application)
+ set(detect_runtime(default_runtime), "runtime") if framework.prompt_for_runtime?
+ end
+ default_command = manifest "command"
+ set ask("Start Command", :default => default_command), "command" if framework.require_start_command?
+
+ url_template = manifest("url") || DEFAULTS["url"]
+ url_resolved = url_template.dup
+ resolve_lexically(url_resolved)
+
+ if !framework.require_url?
+ url_resolved = "None"
+ end
+ url = ask("Application Deployed URL", :default => url_resolved)
+
+ if url == url_resolved && url != "None"
+ url = url_template
+ end
+
+ # common error case is for prompted users to answer y or Y or yes or
+ # YES to this ask() resulting in an unintended URL of y. Special
+ # case this common error
+ url = url_resolved if YES_SET.member? url
+
+ if(url == "None")
+ url = nil
+ end
+
+ set url, "url"
+
+ default_mem = manifest("mem")
+ default_mem = framework.memory(manifest("runtime")) if not default_mem
set ask(
"Memory reservation",
:default =>
- manifest("mem") ||
- manifest("framework", "info", "mem") ||
+ default_mem ||
DEFAULTS["mem"],
:choices => ["128M", "256M", "512M", "1G", "2G"]
), "mem"
@@ -184,6 +206,24 @@ def detect_framework(prompt_ok = true)
framework
end
+ # Detect the appropriate runtime.
+ def detect_runtime(default, prompt_ok=true)
+ runtime = nil
+ runtime_keys=[]
+ runtimes_info.keys.each {|runtime_key| runtime_keys << runtime_key.dup }
+ runtime_keys.sort!
+ if prompt_ok
+ runtime = ask(
+ "Select Runtime",
+ :indexed => true,
+ :default => default,
+ :choices => runtime_keys
+ )
+ display "Selected #{runtime}"
+ end
+ runtime
+ end
+
def bind_services(user_services, chosen = 0)
svcname = ask(
"Which one?",
View
9 spec/assets/standalone_app_info.txt
@@ -0,0 +1,9 @@
+HTTP/1.1 200 OK
+Server: nginx/0.7.65
+Date: Fri, 04 Mar 2011 02:56:21 GMT
+Content-Type: application/json
+Connection: keep-alive
+Keep-Alive: timeout=20
+Content-Length: 243
+
+{"resources":{"memory":64},"uris":["foo.vcap.me"],"staging":{"runtime":"ruby18" ,"framework":"standalone"},"state":"STARTED","instances":1,"name":"foo","meta":{"version":1,"created":1299207348},"services":[],"runningInstances":1}
2 spec/assets/tests
@@ -1 +1 @@
-Subproject commit 6a32f9c4faa99385a32d7b5d3529a0ac446100a6
+Subproject commit 4b937e6a951f674dc88f466d255de5d9a20f38d3
View
156 spec/unit/command_apps_spec.rb
@@ -88,4 +88,160 @@
expect { command.update('foo')}.to raise_error(/Can't deploy application containing links/)
end
+ it 'should not fail when there is an attempt to update an app using a single file' do
+ @client = VMC::Client.new(@local_target, @auth_token)
+
+ login_path = "#{@local_target}/users/#{@user}/tokens"
+ stub_request(:post, login_path).to_return(File.new(spec_asset('login_success.txt')))
+ info_path = "#{@local_target}/#{VMC::INFO_PATH}"
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
+
+ app = spec_asset('tests/standalone/simple_ruby_app/simple.rb')
+ options = {
+ :name => 'foo',
+ :uris => ['foo.vcap.me'],
+ :instances => 1,
+ :staging => { :framework => 'standalone', :runtime => 'ruby18', :command=>"ruby simple.rb" },
+ :path => app,
+ :resources => { :memory => 128 }
+ }
+ command = VMC::Cli::Command::Apps.new(options)
+ command.client(@client)
+
+ app_path = "#{@local_target}/#{VMC::APPS_PATH}/foo"
+ stub_request(:get, app_path).to_return(File.new(spec_asset('standalone_app_info.txt')))
+
+ resource_path = "#{@local_target}/#{VMC::RESOURCES_PATH}"
+ stub_request(:post, resource_path).to_return(File.new(spec_asset('resources_return.txt')))
+
+ app_upload_path = "#{@local_target}/#{VMC::APPS_PATH}/foo/application"
+ stub_request(:post, app_upload_path)
+
+ stub_request(:put, app_path)
+
+ # Both 'vmc push ..' and 'vmc update ..' ultimately end up calling upload_app_bits
+ command.update('foo')
+
+ a_request(:post, app_upload_path).should have_been_made.once
+ a_request(:put, app_path).should have_been_made.once
+
+ end
+
+ it 'should not fail when there is an attempt to update an app using a single WAR file' do
+ @client = VMC::Client.new(@local_target, @auth_token)
+
+ login_path = "#{@local_target}/users/#{@user}/tokens"
+ stub_request(:post, login_path).to_return(File.new(spec_asset('login_success.txt')))
+ info_path = "#{@local_target}/#{VMC::INFO_PATH}"
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
+
+ app = spec_asset('tests/spring/spring-osgi-hello/target/hello.war')
+ options = {
+ :name => 'foo',
+ :uris => ['foo.vcap.me'],
+ :instances => 1,
+ :staging => { :framework => 'spring'},
+ :path => app,
+ :resources => { :memory => 512 }
+ }
+ command = VMC::Cli::Command::Apps.new(options)
+ command.client(@client)
+
+ app_path = "#{@local_target}/#{VMC::APPS_PATH}/foo"
+ stub_request(:get, app_path).to_return(File.new(spec_asset('standalone_app_info.txt')))
+
+ resource_path = "#{@local_target}/#{VMC::RESOURCES_PATH}"
+ stub_request(:post, resource_path).to_return(File.new(spec_asset('resources_return.txt')))
+
+ app_upload_path = "#{@local_target}/#{VMC::APPS_PATH}/foo/application"
+ stub_request(:post, app_upload_path)
+
+ stub_request(:put, app_path)
+
+ # Both 'vmc push ..' and 'vmc update ..' ultimately end up calling upload_app_bits
+ command.update('foo')
+
+ a_request(:post, app_upload_path).should have_been_made.once
+ a_request(:put, app_path).should have_been_made.once
+
+ end
+
+ it 'should not fail when there is an attempt to update an app using a single zip file' do
+ @client = VMC::Client.new(@local_target, @auth_token)
+
+ login_path = "#{@local_target}/users/#{@user}/tokens"
+ stub_request(:post, login_path).to_return(File.new(spec_asset('login_success.txt')))
+ info_path = "#{@local_target}/#{VMC::INFO_PATH}"
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
+
+ app = spec_asset('tests/standalone/java_app/target/zip/standalone-java-app-1.0.0.BUILD-SNAPSHOT-jar.zip')
+ options = {
+ :name => 'foo',
+ :uris => ['foo.vcap.me'],
+ :instances => 1,
+ :staging => { :framework => 'standalone', :runtime => 'java', :command=>"java HelloCloud" },
+ :path => app,
+ :resources => { :memory => 128 }
+ }
+ command = VMC::Cli::Command::Apps.new(options)
+ command.client(@client)
+
+ app_path = "#{@local_target}/#{VMC::APPS_PATH}/foo"
+ stub_request(:get, app_path).to_return(File.new(spec_asset('standalone_app_info.txt')))
+
+ resource_path = "#{@local_target}/#{VMC::RESOURCES_PATH}"
+ stub_request(:post, resource_path).to_return(File.new(spec_asset('resources_return.txt')))
+
+ app_upload_path = "#{@local_target}/#{VMC::APPS_PATH}/foo/application"
+ stub_request(:post, app_upload_path)
+
+ stub_request(:put, app_path)
+
+ # Both 'vmc push ..' and 'vmc update ..' ultimately end up calling upload_app_bits
+ command.update('foo')
+
+ a_request(:post, app_upload_path).should have_been_made.once
+ a_request(:put, app_path).should have_been_made.once
+
+ end
+
+ it 'should not fail when there is an attempt to update an app using a dir containing a zip file' do
+ @client = VMC::Client.new(@local_target, @auth_token)
+
+ login_path = "#{@local_target}/users/#{@user}/tokens"
+ stub_request(:post, login_path).to_return(File.new(spec_asset('login_success.txt')))
+ info_path = "#{@local_target}/#{VMC::INFO_PATH}"
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
+
+ app = spec_asset('tests/standalone/java_app/target/zip')
+ options = {
+ :name => 'foo',
+ :uris => ['foo.vcap.me'],
+ :instances => 1,
+ :staging => { :framework => 'standalone', :runtime => 'java', :command=>"java HelloCloud" },
+ :path => app,
+ :resources => { :memory => 128 }
+ }
+ command = VMC::Cli::Command::Apps.new(options)
+ command.client(@client)
+
+ app_path = "#{@local_target}/#{VMC::APPS_PATH}/foo"
+ stub_request(:get, app_path).to_return(File.new(spec_asset('standalone_app_info.txt')))
+
+ resource_path = "#{@local_target}/#{VMC::RESOURCES_PATH}"
+ stub_request(:post, resource_path).to_return(File.new(spec_asset('resources_return.txt')))
+
+ app_upload_path = "#{@local_target}/#{VMC::APPS_PATH}/foo/application"
+ stub_request(:post, app_upload_path)
+
+ stub_request(:put, app_path)
+
+ # Both 'vmc push ..' and 'vmc update ..' ultimately end up calling upload_app_bits
+ command.update('foo')
+
+ a_request(:post, app_upload_path).should have_been_made.once
+ a_request(:put, app_path).should have_been_made.once
+
+ end
+
end
View
156 spec/unit/frameworks_spec.rb
@@ -11,89 +11,211 @@
it 'should be able to detect a Java web app war' do
app = spec_asset('tests/java_web/java_tiny_app/target')
- framework(app).should =~ /Java Web/
+ framework(app).to_s.should =~ /Java Web/
end
it 'should be able to detect an exploded Java web app' do
app = spec_asset('tests/java_web/java_tiny_app/target')
- framework(get_war_file(app), true).should =~ /Java Web/
+ framework(get_war_file(app), true).to_s.should =~ /Java Web/
end
it 'should be able to detect a Spring web app war' do
app = spec_asset('tests/spring/roo-guestbook/target')
- framework(app).should =~ /Spring/
+ framework(app).to_s.should =~ /Spring/
end
it 'should be able to detect an exploded Spring web app' do
app = spec_asset('tests/spring/roo-guestbook/target/')
- framework(get_war_file(app), true).should =~ /Spring/
+ framework(get_war_file(app), true).to_s.should =~ /Spring/
end
it 'should be able to detect a Spring web app war that uses OSGi-style jars' do
app = spec_asset('tests/spring/spring-osgi-hello/target')
- framework(app).should =~ /Spring/
+ framework(app).to_s.should =~ /Spring/
end
it 'should be able to detect an exploded Spring web app that uses OSGi-style jars' do
app = spec_asset('tests/spring/spring-osgi-hello/target')
- framework(get_war_file(app), true).should =~ /Spring/
+ framework(get_war_file(app), true).to_s.should =~ /Spring/
end
it 'should be able to detect a Lift web app war' do
app = spec_asset('tests/lift/hello_lift/target')
- framework(app).should =~ /Lift/
+ framework(app).to_s.should =~ /Lift/
+ end
+
+ it 'should be able to detect a Lift web app war file' do
+ app = spec_asset('tests/lift/hello_lift/target/scala_lift-1.0.war')
+ framework(app).to_s.should =~ /Lift/
end
it 'should be able to detect an exploded Lift web app' do
app = spec_asset('tests/lift/hello_lift/target')
- framework(get_war_file(app), true).should =~ /Lift/
+ framework(get_war_file(app), true).to_s.should =~ /Lift/
end
it 'should be able to detect a Grails web app war' do
pending "Availability of a fully functional maven plugin for grails"
app = spec_asset('tests/grails/guestbook/target')
- framework(app).should =~ /Grails/
+ framework(app).to_s.should =~ /Grails/
end
it 'should be able to detect an exploded Grails web app' do
pending "Availability of a fully functional maven plugin for grails"
app = spec_asset('tests/grails/guestbook/target')
- framework(get_war_file(app), true).should =~ /Grails/
+ framework(get_war_file(app), true).to_s.should =~ /Grails/
end
it 'should be able to detect a Rails3 app' do
app = spec_asset('tests/rails3/hello_vcap')
- framework(app).should =~ /Rails/
+ framework(app).to_s.should =~ /Rails/
end
it 'should be able to detect a Sinatra app' do
app = spec_asset('tests/sinatra/hello_vcap')
- framework(app).should =~ /Sinatra/
+ framework(app).to_s.should =~ /Sinatra/
end
it 'should be able to detect a Rack app' do
app = spec_asset('tests/rack/app_rack_service')
- framework(app,false,[["rack"]]).should =~ /Rack/
+ framework(app,false,[["rack"]]).to_s.should =~ /Rack/
end
it 'should fall back to Sinatra detection if Rack framework not supported' do
app = spec_asset('tests/rack/app_rack_service')
- framework(app,false).should =~ /Sinatra/
+ framework(app,false).to_s.should =~ /Sinatra/
end
it 'should be able to detect a Node.js app' do
app = spec_asset('tests/node/hello_vcap')
- framework(app).should=~ /Node.js/
+ framework(app).to_s.should=~ /Node.js/
+ end
+
+ describe 'standalone app support' do
+ it 'should fall back to Standalone app from single non-WAR file' do
+ app = spec_asset("tests/standalone/java_app/target/" +
+ "standalone-java-app-1.0.0.BUILD-SNAPSHOT.jar")
+ framework(app,false,[["standalone"]]).to_s.should=~ /Standalone/
+ end
+
+ it 'should fall back to nil if Standalone framework not supported for single non-WAR file' do
+ app = spec_asset("tests/standalone/java_app/target/" +
+ "standalone-java-app-1.0.0.BUILD-SNAPSHOT.jar")
+ framework(app).should == nil
+ end
+
+ it 'should fall back to Standalone app if dir does not match other frameworks' do
+ app = spec_asset('tests/standalone/python_app')
+ framework(app,false,[["standalone"]]).to_s.should=~ /Standalone/
+ end
+
+ it 'should fall back to nil if Standalone framework not supported for dir' do
+ app = spec_asset('tests/standalone/python_app')
+ framework(app).should == nil
+ end
+
+ it 'should detect default Java runtime with a single jar' do
+ app = spec_asset("tests/standalone/java_app/target/" +
+ "standalone-java-app-1.0.0.BUILD-SNAPSHOT.jar")
+ framework(app,false,[["standalone"]]).default_runtime(app).should == "java"
+ end
+
+ it 'should detect default Java runtime with a zip of jars' do
+ app = spec_asset("tests/standalone/java_app/target/zip/" +
+ "standalone-java-app-1.0.0.BUILD-SNAPSHOT-jar.zip")
+ framework(app,false,[["standalone"]]).default_runtime(app).should == "java"
+ end
+
+ it 'should detect default Java runtime with a dir containing zip of jar files' do
+ app = spec_asset('tests/standalone/java_app/target/zip')
+ framework(app,false,[["standalone"]]).default_runtime(app).should == "java"
+ end
+
+ it 'should detect default Java runtime with a dir containing jar files' do
+ app = spec_asset('tests/standalone/java_app/target')
+ framework(app,false,[["standalone"]]).default_runtime(app).should == "java"
+ end
+
+ it 'should detect default Java runtime with a single class' do
+ app = spec_asset('tests/standalone/java_app/target/classes/HelloCloud.class')
+ framework(app,false,[["standalone"]]).default_runtime(app).should == "java"
+ end
+
+ it 'should detect default Java runtime with a dir containing class files' do
+ app = spec_asset('tests/standalone/java_app/target/classes')
+ framework(app,false,[["standalone"]]).default_runtime(app).should == "java"
+ end
+
+ it 'should detect default Ruby runtime with a single rb file' do
+ app = spec_asset('tests/standalone/ruby_app/main.rb')
+ framework(app,false,[["standalone"]]).default_runtime(app).should == "ruby18"
+ end
+
+ it 'should detect default Ruby runtime with a dir containing rb files' do
+ app = spec_asset('tests/standalone/simple_ruby_app')
+ framework(app,false,[["standalone"]]).default_runtime(app).should == "ruby18"
+ end
+
+ it 'should return nil for default runtime if framework is not standalone' do
+ app = spec_asset('tests/lift/hello_lift/target')
+ framework(app,false,[["standalone"]]).default_runtime(app).should == nil
+ end
+
+ it 'should return nil for default runtime if zip does not contain jars' do
+ app = spec_asset("tests/standalone/python_app/target/zip/" +
+ "standalone-python-1.0.0.BUILD-SNAPSHOT-script.zip")
+ framework(app,false,[["standalone"]]).default_runtime(app).should == nil
+ end
+
+ it 'should return nil for default runtime if dir contains zip with no jars' do
+ app = spec_asset('tests/standalone/python_app/target/zip')
+ framework(app,false,[["standalone"]]).default_runtime(app).should == nil
+ end
+
+ it 'should return nil for default runtime if file does not match any rules' do
+ app = spec_asset('tests/standalone/python_app')
+ framework(app,false,[["standalone"]]).default_runtime(app).should == nil
+ end
+
+ it 'should return expected default memory for standalone Java apps' do
+ app = spec_asset('tests/standalone/java_app/target')
+ framework(app,false,[["standalone"]]).memory("java").should == '512M'
+ end
+
+ it 'should return expected default memory for standalone Ruby 1.8 apps' do
+ app = spec_asset('tests/standalone/ruby_app/main.rb')
+ framework(app,false,[["standalone"]]).memory("ruby18").should == '128M'
+ end
+
+ it 'should return expected default memory for standalone Ruby 1.9 apps' do
+ app = spec_asset('tests/standalone/ruby_app/main.rb')
+ framework(app,false,[["standalone"]]).memory("ruby19").should == '128M'
+ end
+
+ it 'should return expected default memory for standalone PHP apps' do
+ app = spec_asset('tests/standalone/php_app')
+ framework(app,false,[["standalone"]]).memory("php").should == '128M'
+ end
+
+ it 'should return expected default memory for standalone apps with other runtimes' do
+ app = spec_asset('tests/standalone/python_app')
+ framework(app,false,[["standalone"]]).memory("python").should == '64M'
+ end
+
+ it 'should return expected default memory for non-standalone apps' do
+ app = spec_asset('tests/rails3/hello_vcap')
+ framework(app).mem.should == '256M'
+ end
end
def framework app, explode=false, available_frameworks=[]
unless explode == true
- return VMC::Cli::Framework.detect(app, available_frameworks).to_s
+ return VMC::Cli::Framework.detect(app, available_frameworks)
end
Dir.mktmpdir {|dir|
exploded_dir = File.join(dir, "exploded")
VMC::Cli::ZipUtil.unpack(app, exploded_dir)
- VMC::Cli::Framework.detect(exploded_dir, available_frameworks).to_s
+ VMC::Cli::Framework.detect(exploded_dir, available_frameworks)
}
end

0 comments on commit df63c09

Please sign in to comment.