Compare commits

...

45 Commits

Author SHA1 Message Date
David Dollar
90356ca41d Regenerated gemspec for version 0.4.3 2010-06-23 19:01:56 -04:00
David Dollar
2ce3a15bb7 dont die if there are no docs to commit 2010-06-23 19:01:54 -04:00
David Dollar
f960277ae8 0.4.3 2010-06-23 19:01:07 -04:00
David Dollar
4f5402af4a update readme 2010-06-23 19:00:57 -04:00
David Dollar
a27f964881 tweak docs 2010-06-23 19:00:55 -04:00
David Dollar
cf008385b4 update readme on man build 2010-06-23 18:59:56 -04:00
David Dollar
f633a579d6 update readme 2010-06-23 18:59:41 -04:00
David Dollar
ea90bf3615 update docs 2010-06-23 18:58:37 -04:00
David Dollar
c65c71b1c0 update docs 2010-06-23 18:58:17 -04:00
David Dollar
6f10f4f014 fix up readme 2010-06-23 18:57:13 -04:00
David Dollar
be6d1b805c Regenerated gemspec for version 0.4.2 2010-06-23 18:54:31 -04:00
David Dollar
58e936a7e2 0.4.2 2010-06-23 18:54:29 -04:00
David Dollar
d4f29d6909 back to master after done 2010-06-23 18:54:17 -04:00
David Dollar
571163795f task to build pages 2010-06-23 18:53:20 -04:00
David Dollar
845ee9ef38 dont store man in repo 2010-06-23 18:50:36 -04:00
David Dollar
d5d774c9c2 Regenerated gemspec for version 0.4.1 2010-06-23 18:20:00 -04:00
David Dollar
b77952ff7f updating man pages 2010-06-23 18:19:59 -04:00
David Dollar
3495fa2fea 0.4.1 2010-06-23 18:19:57 -04:00
David Dollar
4741dceeb0 build man on release 2010-06-23 18:19:50 -04:00
David Dollar
dc1cb08d27 updating man pages 2010-06-23 18:19:38 -04:00
David Dollar
b51e8046ce 0.4.0 2010-06-23 18:19:23 -04:00
David Dollar
922eb7438e add manpage 2010-06-23 18:17:55 -04:00
David Dollar
6811a8d96a massive reworking of command line interface 2010-06-23 17:51:12 -04:00
David Dollar
0f7eec061d Regenerated gemspec for version 0.3.2 2010-06-22 17:20:21 -04:00
David Dollar
27e53eb916 0.3.2 2010-06-22 17:20:15 -04:00
David Dollar
b123e6b3c5 change the output format 2010-06-22 17:20:01 -04:00
David Dollar
c2000484bb capture PTY::ChildExited 2010-06-22 17:19:47 -04:00
David Dollar
75f0ce4b9c Regenerated gemspec for version 0.3.1 2010-06-22 16:48:41 -04:00
David Dollar
d508d44fd2 0.3.1 2010-06-22 16:48:39 -04:00
David Dollar
35cc880d40 clean up messaging 2010-06-22 16:48:16 -04:00
David Dollar
6434db289b 0.3.0 2010-06-22 16:33:48 -04:00
David Dollar
1a118ee92b fix up docs 2010-06-22 16:33:16 -04:00
David Dollar
7bd176063c fix up specs 2010-06-22 16:29:49 -04:00
David Dollar
fff958f7b6 add colorization 2010-06-22 16:28:08 -04:00
David Dollar
7888ee8c52 print to stdout, die when any child process dies 2010-06-22 16:15:27 -04:00
David Dollar
a6197c183e change example 2010-06-22 16:15:17 -04:00
David Dollar
41a0620126 Merge branch 'master' of github.com:ddollar/foreman 2010-06-11 21:52:07 -04:00
David Dollar
86654d7918 update docs 2010-06-10 15:27:18 -04:00
David Dollar
9929165d17 update docs 2010-06-10 15:26:28 -04:00
David Dollar
2b8d575aab 0.2.0 2010-06-09 12:32:33 -04:00
David Dollar
56f8603a5d first attempt at screen-based running 2010-06-09 12:13:02 -04:00
David Dollar
3f48d7c541 add execute command 2010-06-09 11:51:18 -04:00
David Dollar
675ad2630d cleanup 2010-06-09 11:51:10 -04:00
David Dollar
9004bf67e1 dont roll back to 1 every export 2010-05-21 15:38:35 -04:00
David Dollar
19c425d200 add gemcutter tasks 2010-05-21 15:32:51 -04:00
22 changed files with 436 additions and 203 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,6 @@
coverage
example/log/*
man/*.?
man/*.html
man/*.markdown
pkg

87
README.markdown Normal file
View File

@@ -0,0 +1,87 @@
foreman(1) -- manage Procfile-based applications
================================================
## SYNOPSIS
`foreman start [process]`<br>
`foreman export <var>format</var> [location]`
## DESCRIPTION
**Foreman** is a manager for Procfile-based applications. Its aim is to
abstract away the details of the Procfile format, and allow you to either run
your application directly or export it to some other process management
format.
## RUNNING
`foreman start` is used to run your application directly from the command line.
If no additional parameters are passed, foreman will run one instance of each
type of process defined in your Procfile.
If a parameter is passed, foreman will run one instance of the specified
application type.
The following options control how the application is run:
* `-s`, `--screen`:
Run the application as a series of screen windows rather than interleaved
in stdout.
## EXPORTING
`foreman export` is used to export your application to another process
management format.
An location to export can be passed as an argument. This argument may be
either required or optional depending on the export format.
The following options control how the application is run:
* `-a`, `--app`:
Use this name rather than the application's root directory name as the
name of the application when exporting.
* `-c`, `--concurrency`:
Specify the number of each process type to run. The value passed in
should be in the format `process=num,process=num`.
## OPTIONS
These options control all modes of foreman's operation.
* `-p`, `--procfile`
Specify an alternate location for the application's Procfile. This file's
containing directory will be assumed to be the root directory of the
application.
## EXAMPLES
Start one instance of each process type, interleave the output on stdout:
$ foreman start
Export the application in upstart format:
$ foreman export upstart /etc/init
Run one process type from the application defined in a specific Procfile:
$ foreman start alpha -p ~/app/Procfile
## COPYRIGHT
Foreman is Copyright (C) 2010 David Dollar <http://daviddollar.org>
[SYNOPSIS]: #SYNOPSIS "SYNOPSIS"
[DESCRIPTION]: #DESCRIPTION "DESCRIPTION"
[RUNNING]: #RUNNING "RUNNING"
[EXPORTING]: #EXPORTING "EXPORTING"
[OPTIONS]: #OPTIONS "OPTIONS"
[EXAMPLES]: #EXAMPLES "EXAMPLES"
[COPYRIGHT]: #COPYRIGHT "COPYRIGHT"
[foreman(1)]: foreman.1.html

View File

@@ -1,77 +0,0 @@
= Foreman
=== Procfile
alpha ./bin/alpha
bravo ./bin/bravo some args
charlie ./bin/charlie -n 5
== Development mode
=== Running
$ foreman start
[foreman] [Tue May 18 01:27:08 UTC 2010] [alpha] started with pid 4393
[foreman] [Tue May 18 01:27:08 UTC 2010] [bravo] started with pid 4394
[foreman] [Tue May 18 01:27:08 UTC 2010] [charlie] started with pid 4395
=== Standardized Logging
log/alpha.log
log/bravo.log
log/charlie.log
== Upstart
=== Export to upstart scripts
$ foreman export sampleapp
$ initctl list | grep sampleapp
sampleapp start/running
sampleapp-alpha (1) start/running, process 4204
sampleapp-bravo (1) start/running, process 4589
sampleapp-charlie (1) start/running, process 4597
=== Change process concurrency levels
$ foreman scale sampleapp alpha 4
sampleapp-alpha (2) start/running, process 4164
sampleapp-alpha (3) start/running, process 4166
sampleapp-alpha (4) start/running, process 4168
$ initctl list | grep sampleapp
sampleapp start/running
sampleapp-alpha (4) start/running, process 4168
sampleapp-alpha (3) start/running, process 4166
sampleapp-alpha (2) start/running, process 4164
sampleapp-alpha (1) start/running, process 4204
sampleapp-bravo (1) start/running, process 4589
sampleapp-charlie (1) start/running, process 4597
$ foreman scale sampleapp alpha 1
sampleapp-alpha stop/waiting
sampleapp-alpha stop/waiting
sampleapp-alpha stop/waiting
=== Good Upstart citizen
All Upstart commands work as expected
$ start sampleapp
$ stop sampleapp
$ restart sampleapp
=== Standardized Logging
/var/log/sampleapp/alpha.log
/var/log/sampleapp/bravo.log
/var/log/sampleapp/charlie.log
== License
MIT
== Copyright
(c) 2010 David Dollar

View File

@@ -1,11 +1,12 @@
require "rubygems"
require "rake"
require "rspec"
require "rspec/core/rake_task"
$:.unshift File.expand_path("../lib", __FILE__)
require "foreman"
task :default => :spec
task :release => :man
desc "Run all specs"
Rspec::Core::RakeTask.new(:spec) do |t|
@@ -23,6 +24,29 @@ Rspec::Core::RakeTask.new("rcov:build") do |t|
t.rcov_opts = [ "--exclude", Gem.default_dir , "--exclude", "spec" ]
end
desc 'Build the manual'
task :man do
ENV['RONN_MANUAL'] = "Foreman Manual"
ENV['RONN_ORGANIZATION'] = "Foreman #{Foreman::VERSION}"
sh "ronn -w -s toc -r5 --markdown man/*.ronn"
sh "cp man/foreman.1.markdown README.markdown"
sh "git add README.markdown"
sh "git commit -m 'update readme' || echo 'nothing to commit'"
end
task :pages => :man do
sh %{
cp man/foreman.1.html /tmp/foreman.1.html
git checkout gh-pages
rm ./index.html
cp /tmp/foreman.1.html ./index.html
git add -u index.html
git commit -m "rebuilding man page"
git push origin -f gh-pages
git checkout master
}
end
######################################################
begin
@@ -53,8 +77,10 @@ begin
s.add_development_dependency 'rr', '~> 0.10.11'
s.add_development_dependency 'rspec', '~> 2.0.0'
s.add_dependency 'term-ansicolor', '~> 1.0.5'
s.add_dependency 'thor', '~> 0.13.6'
end
Jeweler::GemcutterTasks.new
rescue LoadError
puts "Jeweler not available. Install it with: sudo gem install jeweler"
end

View File

@@ -1,3 +1,2 @@
neverdie ./never_die
diealot ./die_alot
error ./error
ticker ./ticker
error ./error

View File

@@ -1,5 +0,0 @@
#!/usr/bin/env ruby
puts "sleeping for 2s then dying"
sleep 2
exit 0

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env ruby
puts "will error in 10s"
sleep 10
sleep 5
raise "Dying"

View File

@@ -2,6 +2,5 @@
while true
puts "tick"
$stdout.flush
sleep 5
sleep 1
end

View File

@@ -0,0 +1,13 @@
pre-start script
bash << "EOF"
mkdir -p /var/log/<%= app %>
<% engine.processes.keys.sort.each do |process| %>
<% 1.upto(concurrency[process]).each do |num| %>
start <%=app%>-<%=process%>-<%=num%>
<% end %>
<% end %>
EOF
end script

View File

@@ -0,0 +1,5 @@
stop on stopping <%= app %>
respawn
chdir <%= engine.directory %>
exec <%= process.command %> >> /var/log/<%=app%>/<%=process.name%>-<%=num%>.log 2>&1

View File

@@ -5,17 +5,17 @@
Gem::Specification.new do |s|
s.name = %q{foreman}
s.version = "0.1.0"
s.version = "0.4.3"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["David Dollar"]
s.date = %q{2010-05-21}
s.date = %q{2010-06-23}
s.default_executable = %q{foreman}
s.description = %q{Process manager for applications with multiple components}
s.email = %q{ddollar@gmail.com}
s.executables = ["foreman"]
s.extra_rdoc_files = [
"README.rdoc"
"README.markdown"
]
s.files = [
"Rakefile",
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
"lib/foreman/configuration.rb",
"lib/foreman/engine.rb",
"lib/foreman/export.rb",
"lib/foreman/export/base.rb",
"lib/foreman/export/upstart.rb",
"lib/foreman/process.rb",
"spec/foreman/cli_spec.rb",
@@ -63,6 +64,7 @@ Gem::Specification.new do |s|
s.add_development_dependency(%q<rcov>, ["~> 0.9.8"])
s.add_development_dependency(%q<rr>, ["~> 0.10.11"])
s.add_development_dependency(%q<rspec>, ["~> 2.0.0"])
s.add_runtime_dependency(%q<term-ansicolor>, ["~> 1.0.5"])
s.add_runtime_dependency(%q<thor>, ["~> 0.13.6"])
else
s.add_dependency(%q<fakefs>, ["~> 0.2.1"])
@@ -70,6 +72,7 @@ Gem::Specification.new do |s|
s.add_dependency(%q<rcov>, ["~> 0.9.8"])
s.add_dependency(%q<rr>, ["~> 0.10.11"])
s.add_dependency(%q<rspec>, ["~> 2.0.0"])
s.add_dependency(%q<term-ansicolor>, ["~> 1.0.5"])
s.add_dependency(%q<thor>, ["~> 0.13.6"])
end
else
@@ -78,6 +81,7 @@ Gem::Specification.new do |s|
s.add_dependency(%q<rcov>, ["~> 0.9.8"])
s.add_dependency(%q<rr>, ["~> 0.10.11"])
s.add_dependency(%q<rspec>, ["~> 2.0.0"])
s.add_dependency(%q<term-ansicolor>, ["~> 1.0.5"])
s.add_dependency(%q<thor>, ["~> 0.13.6"])
end
end

View File

@@ -1,6 +1,6 @@
module Foreman
VERSION = "0.1.0"
VERSION = "0.4.3"
class AppDoesNotExist < Exception; end

View File

@@ -6,32 +6,58 @@ require "thor"
class Foreman::CLI < Thor
desc "start [PROCFILE]", "Run the app described in PROCFILE"
class_option :procfile, :type => :string, :aliases => "-p", :desc => "Default: ./Procfile"
def start(procfile="Procfile")
error "#{procfile} does not exist." unless procfile_exists?(procfile)
Foreman::Engine.new(procfile).start
desc "start [PROCESS]", "Start the application, or a specific process"
method_option :screen, :type => :boolean, :aliases => "-s"
def start(process=nil)
check_procfile!
if process
engine.execute(process)
elsif options[:screen]
engine.screen
else
engine.start
end
end
desc "export APP [PROCFILE] [FORMAT]", "Export the app described in PROCFILE as APP to another FORMAT"
desc "export FORMAT LOCATION", "Export the application to another process management format"
def export(app, procfile="Procfile", format="upstart")
error "#{procfile} does not exist." unless procfile_exists?(procfile)
method_option :app, :type => :string, :aliases => "-a"
method_option :concurrency, :type => :string, :aliases => "-c",
:banner => '"alpha=5,bar=3"'
def export(format, location=nil)
check_procfile!
formatter = case format
when "upstart" then Foreman::Export::Upstart
else error "Unknown export format: #{format}."
end
formatter.new(Foreman::Engine.new(procfile)).export(app)
formatter.new(engine).export(location,
:name => options[:app],
:concurrency => options[:concurrency]
)
rescue Foreman::Export::Exception => ex
error ex.message
end
desc "scale APP PROCESS AMOUNT", "Change the concurrency of a given process type"
private ######################################################################
def scale(app, process, amount)
config = Foreman::Configuration.new(app)
error "No such process: #{process}." unless config.processes[process]
config.scale(process, amount)
def check_procfile!
error("Procfile does not exist.") unless File.exist?(procfile)
end
def engine
@engine ||= Foreman::Engine.new(procfile)
end
def procfile
options[:procfile] || "./Procfile"
end
private ######################################################################

View File

@@ -1,11 +1,18 @@
require "foreman"
require "foreman/process"
require "pty"
require "tempfile"
require "term/ansicolor"
class Foreman::Engine
attr_reader :procfile
attr_reader :directory
extend Term::ANSIColor
COLORS = [ cyan, yellow, green, magenta, on_blue ]
def initialize(procfile)
@procfile = read_procfile(procfile)
@directory = File.expand_path(File.dirname(procfile))
@@ -16,6 +23,7 @@ class Foreman::Engine
procfile.split("\n").inject({}) do |hash, line|
next if line.strip == ""
process = Foreman::Process.new(*line.split(" ", 2))
process.color = next_color
hash.update(process.name => process)
end
end
@@ -31,37 +39,84 @@ class Foreman::Engine
trap("TERM") { kill_and_exit("TERM") }
trap("INT") { kill_and_exit("INT") }
run_loop
watch_for_termination
end
def screen
tempfile = Tempfile.new("foreman")
tempfile.puts "sessionname foreman"
processes.each do |name, process|
tempfile.puts "screen -t #{name} #{process.command}"
end
tempfile.close
system "screen -c #{tempfile.path}"
tempfile.delete
end
def execute(name)
run(processes[name], false)
end
private ######################################################################
def fork(process)
pid = Process.fork do
proctitle "ruby: foreman #{process.name}"
Dir.chdir directory do
FileUtils.mkdir_p "log"
system "#{process.command} >>log/#{process.name}.log 2>&1"
exit $?.exitstatus || 255
end
run(process)
end
info "started with pid #{pid}", process
running_processes[pid] = process
end
def run(process, log_to_file=true)
proctitle "ruby: foreman #{process.name}"
Dir.chdir directory do
FileUtils.mkdir_p "log"
command = process.command
begin
PTY.spawn("#{process.command} 2>&1") do |stdin, stdout, pid|
until stdin.eof?
info stdin.gets, process
end
end
rescue PTY::ChildExited, Interrupt
info "process exiting", process
end
end
end
def kill_and_exit(signal="TERM")
info "termination requested"
info "terminating"
running_processes.each do |pid, process|
info "killing pid #{pid}", process
info "killing #{process.name} in pid #{pid}"
Process.kill(signal, pid)
end
exit 0
end
def info(message, process=nil)
puts "[foreman] [#{Time.now.utc}] [#{process ? process.name : "system"}] #{message}"
print process.color if process
print "#{Time.now.strftime("%H:%M:%S")} #{pad_process_name(process)} | "
print Term::ANSIColor.reset
print message.chomp
puts
end
def longest_process_name
@longest_process_name ||= begin
longest = processes.keys.map { |name| name.length }.sort.last
longest = 6 if longest < 6 # system
longest
end
end
def pad_process_name(process)
name = process ? process.name : "system"
name.ljust(longest_process_name)
end
def print_info
@@ -79,17 +134,21 @@ private ######################################################################
File.read(procfile)
end
def run_loop
while true
pid, status = Process.wait2
process = running_processes.delete(pid)
info "exited with code #{status}", process
fork process
end
def watch_for_termination
pid, status = Process.wait2
process = running_processes.delete(pid)
info "process terminated", process
kill_and_exit
end
def running_processes
@running_processes ||= {}
end
def next_color
@current_color ||= -1
@current_color += 1
@current_color >= COLORS.length ? "" : COLORS[@current_color]
end
end

View File

@@ -1,6 +1,7 @@
require "foreman"
module Foreman::Export
class Exception < ::Exception; end
end
require "foreman/export/upstart"

View File

@@ -0,0 +1,48 @@
require "foreman/configuration"
require "foreman/export"
class Foreman::Export::Base
attr_reader :engine
def initialize(engine)
@engine = engine
end
def export
raise "export method must be overridden"
end
private ######################################################################
def error(message)
raise Foreman::Export::Exception.new(message)
end
def say(message)
puts "[foreman export] %s" % message
end
def export_template(name)
File.read(File.expand_path("../../../../export/#{name}", __FILE__))
end
def parse_concurrency(concurrency)
@concurrency ||= begin
pairs = concurrency.to_s.gsub(/\s/, "").split(",")
pairs.inject(Hash.new(1)) do |hash, pair|
process, amount = pair.split("=")
hash.update(process => amount.to_i)
end
end
end
def write_file(filename, contents)
say "writing: #{filename}"
File.open(filename, "w") do |file|
file.puts contents
end
end
end

View File

@@ -1,66 +1,49 @@
require "erb"
require "foreman/configuration"
require "foreman/export"
require "foreman/export/base"
class Foreman::Export::Upstart
class Foreman::Export::Upstart < Foreman::Export::Base
attr_reader :engine
def export(location, options={})
error("Must specify a location") unless location
def initialize(engine)
@engine = engine
end
FileUtils.mkdir_p location
def export(app)
FileUtils.mkdir_p "/etc/foreman"
FileUtils.mkdir_p "/etc/init"
app = options[:app] || File.basename(engine.directory)
config = Foreman::Configuration.new(app)
Dir["#{location}/#{app}*.conf"].each do |file|
say "cleaning up: #{file}"
FileUtils.rm(file)
end
write_file "/etc/init/#{app}.conf", <<-UPSTART_MASTER
pre-start script
concurrency = parse_concurrency(options[:concurrency])
bash << "EOF"
mkdir -p /var/log/#{app}
master_template = export_template("upstart/master.conf.erb")
master_config = ERB.new(master_template).result(binding)
write_file "#{location}/#{app}.conf", master_config
if [ -f /etc/foreman/#{app}.conf ]; then
source /etc/foreman/#{app}.conf
fi
process_template = export_template("upstart/process.conf.erb")
engine.processes.values.each do |process|
1.upto(concurrency[process.name]) do |num|
process_config = ERB.new(process_template).result(binding)
write_file "#{location}/#{app}-#{process.name}-#{num}.conf", process_config
end
end
for process in $( echo "$#{app}_processes" ); do
process_count_config="#{app}_$process"
process_count=${!process_count_config}
for ((i=1; i<=${process_count:=1}; i+=1)); do
start #{app}-$process NUM=$i
done
done
EOF
end script
return
write_file "#{location}/#{app}.conf", <<-UPSTART_MASTER
UPSTART_MASTER
engine.processes.values.each do |process|
write_file "/etc/init/#{app}-#{process.name}.conf", <<-UPSTART_CHILD
instance $NUM
stop on stopping #{app}
respawn
chdir #{engine.directory}
exec #{process.command} >>/var/log/#{app}/#{process.name}.log 2>&1
engine.processes.each do |process|
write_file process_conf, <<-UPSTART_CHILD
UPSTART_CHILD
end
engine.processes.each do |name, process|
config.scale(name, 1)
config.processes[name] ||= 1
end
config.write
end
private ######################################################################
def write_file(filename, contents)
File.open(filename, "w") do |file|
file.puts contents
end
end
end

View File

@@ -4,6 +4,7 @@ class Foreman::Process
attr_reader :name
attr_reader :command
attr_accessor :color
def initialize(name, command)
@name = name

75
man/foreman.1.ronn Normal file
View File

@@ -0,0 +1,75 @@
foreman(1) -- manage Procfile-based applications
================================================
## SYNOPSIS
`foreman start [process]`<br>
`foreman export <format> [location]`
## DESCRIPTION
**Foreman** is a manager for Procfile-based applications. Its aim is to
abstract away the details of the Procfile format, and allow you to either run
your application directly or export it to some other process management
format.
## RUNNING
`foreman start` is used to run your application directly from the command line.
If no additional parameters are passed, foreman will run one instance of each
type of process defined in your Procfile.
If a parameter is passed, foreman will run one instance of the specified
application type.
The following options control how the application is run:
* `-s`, `--screen`:
Run the application as a series of screen windows rather than interleaved
in stdout.
## EXPORTING
`foreman export` is used to export your application to another process
management format.
An location to export can be passed as an argument. This argument may be
either required or optional depending on the export format.
The following options control how the application is run:
* `-a`, `--app`:
Use this name rather than the application's root directory name as the
name of the application when exporting.
* `-c`, `--concurrency`:
Specify the number of each process type to run. The value passed in
should be in the format `process=num,process=num`.
## OPTIONS
These options control all modes of foreman's operation.
* `-p`, `--procfile`
Specify an alternate location for the application's Procfile. This file's
containing directory will be assumed to be the root directory of the
application.
## EXAMPLES
Start one instance of each process type, interleave the output on stdout:
$ foreman start
Export the application in upstart format:
$ foreman export upstart /etc/init
Run one process type from the application defined in a specific Procfile:
$ foreman start alpha -p ~/app/Procfile
## COPYRIGHT
Foreman is Copyright (C) 2010 David Dollar <http://daviddollar.org>

View File

@@ -5,9 +5,7 @@ describe "Foreman::CLI" do
subject { Foreman::CLI.new }
describe "start" do
#let(:engine) { stub_engine }
describe "with a non-existent Procifile" do
describe "with a non-existent Procfile" do
it "prints an error" do
mock_error(subject, "Procfile does not exist.") do
dont_allow.instance_of(Foreman::Engine).start
@@ -28,7 +26,7 @@ describe "Foreman::CLI" do
end
describe "export" do
describe "with a non-existent Procifile" do
describe "with a non-existent Procfile" do
it "prints an error" do
mock_error(subject, "Procfile does not exist.") do
dont_allow.instance_of(Foreman::Engine).export
@@ -43,7 +41,7 @@ describe "Foreman::CLI" do
describe "with an invalid formatter" do
it "prints an error" do
mock_error(subject, "Unknown export format: invalidformatter.") do
subject.export("testapp", "Procfile", "invalidformatter")
subject.export("invalidformatter")
end
end
end
@@ -53,33 +51,11 @@ describe "Foreman::CLI" do
it "runs successfully" do
dont_allow(subject).error
subject.export("testapp")
end
end
end
end
describe "scale" do
describe "without an existing configuration" do
it "displays an error" do
mock_error(subject, "No such process: alpha.") do
subject.scale("testapp", "alpha", "2")
end
end
end
describe "with an existing configuration" do
before(:each) { write_foreman_config("testapp") }
it "scales a process that exists" do
mock.instance_of(Foreman::Configuration).scale("alpha", "2")
subject.scale("testapp", "alpha", "2")
end
it "errors if a process that does not exist is specified" do
mock_error(subject, "No such process: invalidprocess.") do
dont_allow.instance_of(Foreman::Configuration).scale
subject.scale("testapp", "invalidprocess", "2")
mock.instance_of(Foreman::Export::Upstart).export("/tmp/foo", {
:concurrency => nil,
:name => nil
})
subject.export("upstart", "/tmp/foo")
end
end
end

View File

@@ -25,8 +25,16 @@ describe "Foreman::Engine" do
write_procfile
mock(subject).fork(subject.processes["alpha"])
mock(subject).fork(subject.processes["bravo"])
mock(subject).run_loop
mock(subject).watch_for_termination
subject.start
end
end
describe "execute" do
it "runs the processes" do
write_procfile
mock(subject).run(subject.processes["alpha"], false)
subject.execute("alpha")
end
end
end

View File

@@ -1,5 +1,7 @@
require "fakefs/spec_helpers"
require "rubygems"
require "rspec"
require "fakefs/safe"
require "fakefs/spec_helpers"
$:.unshift "lib"